Files

1 line
5.4 MiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "6666235/api-gateway", "files": {"static/index.html": {"6856c86e21f354e55ac082aa94f0bad6feea1279": {"t": 1785746539.2155771, "n": 260450, "h": "4cb3dfef35cbd92c", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"theme-color\" content=\"#0f0f1a\">\n<meta name=\"description\" content=\"AI Hub - 统一 AI 平台\">\n<link rel=\"manifest\" href=\"/static/manifest.json\">\n<link rel=\"apple-touch-icon\" href=\"/static/icon-192.png\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<script src=\"/static/enhancements.js\" defer></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n[data-theme=\"blue\"]{--bg:#0a1628;--bg2:#0f2744;--bg3:#1a3a5c;--text:#e8f4ff;--text2:#88b4d8;--accent:#3b82f6;--accent2:#60a5fa;--border:#1e4976}\n[data-theme=\"green\"]{--bg:#0a1a14;--bg2:#0f2e1f;--bg3:#1a4a32;--text:#e8fff0;--text2:#88d8a8;--accent:#22c55e;--accent2:#4ade80;--border:#1e5c3a}\n[data-theme=\"purple\"]{--bg:#14081a;--bg2:#1f0f2e;--bg3:#321a4a;--text:#f8e8ff;--text2:#b888d8;--accent:#a855f7;--accent2:#c084fc;--border:#4a1e76}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0;overflow-y:auto;overflow-x:hidden}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px;flex:1;overflow-y:auto}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"local-models\"><span class=\"nav-item-icon\">🏠</span> 本地模型</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"traces\"><span class=\"nav-item-icon\">🔍</span> 链路追踪</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n<div class=\"nav-item\" data-page=\"rag\"><span class=\"nav-item-icon\">🔍</span> RAG 检索</div>\n<div class=\"nav-item\" data-page=\"billing\"><span class=\"nav-item-icon\">💳</span> 订阅计费</div>\n<div class=\"nav-item\" data-page=\"rbac\"><span class=\"nav-item-icon\">🛡️</span> 权限管理</div>\n<div class=\"nav-item\" data-page=\"audit\"><span class=\"nav-item-icon\">📜</span> 审计日志</div>\n<div class=\"nav-item\" data-page=\"security\"><span class=\"nav-item-icon\">🔒</span> 安全中心</div>\n<div class=\"nav-item\" data-page=\"monitoring\"><span class=\"nav-item-icon\">📊</span> 系统监控</div>\n<div class=\"nav-item\" data-page=\"tasks\"><span class=\"nav-item-icon\">⚙️</span> 任务队列</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"integrations\"><span class=\"nav-item-icon\">🔗</span> 第三方集成</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"workflows\"><span class=\"nav-item-icon\">🤖</span> Agent 工作流</div>\n<div class=\"nav-item\" data-page=\"code-runner\"><span class=\"nav-item-icon\">▶️</span> 代码运行</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" onclick=\"showHealthDashboard()\"><span class=\"nav-item-icon\">🖥️</span> 系统状态</div>\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\" style=\"display:none\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\" title=\"批量操作\">☑️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div id=\"batchActions\" style=\"display:none;padding:8px;background:var(--bg3);gap:8px;align-items:center\">\n<span style=\"font-size:12px\">已选 <span id=\"selectedCount\">0</span> 个</span>\n<button class=\"btn btn-danger btn-sm\" onclick=\"batchDeleteChats()\">删除</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"batchExportChats()\">导出</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\">取消</button>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"quickReplies\" style=\"display:none;padding:8px 0;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap\"></div>\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateImage()\" title=\"生成图片\">🎨</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateMindmap()\" title=\"生成思维导图\">🧠</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"saveAsTemplate()\" title=\"保存为模板\">💾</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 本地模型页 -->\n<div id=\"page-local-models\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🏠</span> 本地模型 (Ollama)</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">使用 Ollama 运行本地大语言模型,数据完全私有</p>\n<div style=\"display:flex;gap:12px;margin-bottom:20px\">\n<button class=\"btn btn-primary\" onclick=\"loadOllamaModels()\">🔄 刷新模型</button>\n<button class=\"btn btn-ghost\" onclick=\"showPullModelModal()\">📥 拉取模型</button>\n<a href=\"https://ollama.ai\" target=\"_blank\" class=\"btn btn-ghost\">📖 Ollama 官网</a>\n</div>\n<div id=\"ollamaStatus\" style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:16px\"></div>\n<div id=\"ollamaModelList\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 本地模型对话</h4>\n<div class=\"form-group\"><label>选择模型</label><select id=\"ollamaModelSelect\" style=\"width:100%;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select></div>\n<div class=\"form-group\"><label>消息</label><textarea id=\"ollamaMessage\" rows=\"4\" placeholder=\"输入消息...\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"chatWithOllama()\">发送</button>\n<div id=\"ollamaResponse\" style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:8px;min-height:100px;display:none\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚡</span> vLLM 服务</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">高性能推理服务器</p>\n<div class=\"form-group\"><label>vLLM 地址</label><input type=\"text\" id=\"vllmUrl\" value=\"http://localhost:8080\" placeholder=\"http://localhost:8080\"></div>\n<button class=\"btn btn-ghost\" onclick=\"loadVLLMModels()\">检查连接</button>\n<div id=\"vllmStatus\" style=\"margin-top:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">双因素认证 (2FA)<br><small style=\"color:var(--text2)\">使用 Google Authenticator 等应用增强账户安全</small></div><div style=\"display:flex;gap:8px\"><span id=\"2faStatus\" style=\"color:var(--text2)\">未启用</span><button class=\"btn btn-ghost btn-sm\" onclick=\"setup2FA()\" id=\"2faBtn\">设置</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录设备管理</div><button class=\"btn btn-ghost btn-sm\" onclick=\"alert('功能开发中')\">查看设备</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">修改密码</div><button class=\"btn btn-ghost btn-sm\" onclick=\"showChangePasswordModal()\">修改</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px;flex-wrap:wrap\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('blue')\">💙 蓝色</button><button class=\"theme-btn\" onclick=\"setTheme('green')\">💚 绿色</button><button class=\"theme-btn\" onclick=\"setTheme('purple')\">💜 紫色</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复<br><small style=\"color:var(--text2)\">导出/导入所有数据(对话、笔记、记忆、设置)</small></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-primary\" onclick=\"exportAllData()\">📤 导出全部</button><button class=\"btn btn-ghost\" onclick=\"importAllData()\">📥 导入数据</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据库优化<br><small style=\"color:var(--text2)\">清理过期数据,优化数据库性能</small></div><button class=\"btn btn-ghost\" onclick=\"optimizeDatabase()\">🔧 优化数据库</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n<button class=\"btn btn-primary\" onclick=\"showUsageAnalytics()\">📈 详细分析</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 链路追踪页 -->\n<div id=\"page-traces\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔍</span> 链路追踪</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"loadTraces()\">🔄 刷新</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportTraces()\">📥 导出</button>\n</div>\n</div>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:20px\">监控 API 请求的完整调用链路,分析性能瓶颈</p>\n<div id=\"tracesList\"><p style=\"color:var(--text2)\">点击刷新加载追踪记录</p></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 性能概览</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--accent)\" id=\"traceAvgLatency\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">平均延迟</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--success)\" id=\"traceSuccessRate\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">成功率</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--warning)\" id=\"traceCount\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总追踪数</div>\n</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- RAG 检索页 -->\n<div id=\"page-rag\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> RAG 语义检索</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">基于向量的语义搜索,让 AI 理解你的文档内容</p>\n<div class=\"form-group\"><label>选择知识库</label><select id=\"ragKbSelect\" style=\"width:100%;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select></div>\n<div class=\"form-group\"><label>搜索问题</label><input type=\"text\" id=\"ragQuery\" placeholder=\"输入你的问题...\"></div>\n<button class=\"btn btn-primary\" onclick=\"searchRAG()\">🔍 语义搜索</button>\n<button class=\"btn btn-ghost\" onclick=\"chatWithRAG()\" style=\"margin-left:8px\">💬 RAG 对话</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 搜索结果</h4>\n<div id=\"ragResults\" style=\"min-height:100px\"><p style=\"color:var(--text2)\">输入问题后点击搜索</p></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📤</span> 索引文档</h4>\n<div class=\"form-group\"><label>文档内容</label><textarea id=\"ragContent\" rows=\"6\" placeholder=\"粘贴文档内容...\"></textarea></div>\n<div class=\"form-group\"><label>文件名</label><input type=\"text\" id=\"ragFilename\" placeholder=\"document.txt\"></div>\n<button class=\"btn btn-primary\" onclick=\"indexDocument()\">📥 索引文档</button>\n</div>\n</div></div></div></div>\n<!-- 订阅计费页 -->\n<div id=\"page-billing\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💳</span> 订阅计费</h4>\n<div id=\"currentSubscription\" style=\"padding:20px;background:var(--bg);border-radius:12px;margin-bottom:20px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div><div style=\"font-size:12px;color:var(--text2)\">当前套餐</div><div style=\"font-size:24px;font-weight:600\" id=\"currentPlanName\">免费版</div></div>\n<div style=\"text-align:right\"><div style=\"font-size:12px;color:var(--text2)\">剩余额度</div><div style=\"font-size:24px;font-weight:600;color:var(--accent)\" id=\"remainingQuota\">10,000</div></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 套餐选择</h4>\n<div id=\"billingPlans\" class=\"price-cards\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 用量统计</h4>\n<div id=\"usageStats\" style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🧾</span> 发票记录</h4>\n<div id=\"invoiceList\"></div>\n</div>\n</div></div></div></div>\n<!-- 权限管理页 -->\n<div id=\"page-rbac\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🛡️</span> 权限管理</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">基于角色的访问控制 (RBAC)</p>\n<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<div style=\"font-size:12px;color:var(--text2);margin-bottom:8px\">我的权限</div>\n<div id=\"myPermissions\" style=\"display:flex;flex-wrap:wrap;gap:8px\"></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👥</span> 角色列表</h4>\n<div id=\"rolesList\"></div>\n<button class=\"btn btn-ghost\" onclick=\"showCreateRoleModal()\" style=\"margin-top:12px\">+ 创建角色</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> 权限说明</h4>\n<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:12px;font-size:13px\">\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>chat</strong> - 对话功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>notes</strong> - 笔记功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>memory</strong> - 全局记忆</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>image</strong> - 图片生成</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>code</strong> - 代码运行</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>rag</strong> - RAG 检索</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>admin</strong> - 管理功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>*</strong> - 所有权限</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 审计日志页 -->\n<div id=\"page-audit\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📜</span> 审计日志</h4>\n<div style=\"display:flex;gap:8px\">\n<select id=\"auditEventFilter\" style=\"padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\" onchange=\"loadAuditLogs()\">\n<option value=\"\">全部事件</option>\n<option value=\"user.login\">用户登录</option>\n<option value=\"data.export\">数据导出</option>\n<option value=\"settings.change\">设置变更</option>\n<option value=\"payment.create\">支付创建</option>\n<option value=\"security.alert\">安全警报</option>\n</select>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"loadAuditLogs()\">🔄 刷新</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportAuditLogs()\">📥 导出</button>\n</div>\n</div>\n<div id=\"auditLogsList\" style=\"max-height:400px;overflow-y:auto\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 合规报告</h4>\n<div style=\"display:flex;gap:12px;margin-bottom:16px\">\n<button class=\"btn btn-primary\" onclick=\"generateComplianceReport('month')\">月度报告</button>\n<button class=\"btn btn-ghost\" onclick=\"generateComplianceReport('quarter')\">季度报告</button>\n<button class=\"btn btn-ghost\" onclick=\"generateComplianceReport('year')\">年度报告</button>\n</div>\n<div id=\"complianceReport\"></div>\n</div>\n</div></div></div></div>\n<!-- 安全中心页 -->\n<div id=\"page-security\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔒</span> 安全中心</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:20px\">\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"blockedIpsCount\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">封禁 IP</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"failedAttemptsCount\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">失败尝试</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"twoFaUsersCount\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">2FA 用户</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"securityScore\">A</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">安全评分</div>\n</div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"loadSecurityStatus()\">🔄 刷新状态</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> IP 封禁管理</h4>\n<div class=\"form-group\"><label>解封 IP</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"unblockIpInput\" placeholder=\"192.168.1.1\"><button class=\"btn btn-ghost\" onclick=\"unblockIP()\">解封</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">强制密码复杂度<br><small style=\"color:var(--text2)\">要求密码包含大小写、数字和特殊字符</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录失败锁定<br><small style=\"color:var(--text2)\">5次失败后锁定1小时</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">会话超时<br><small style=\"color:var(--text2)\">30天无活动自动登出</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 系统监控页 -->\n<div id=\"page-monitoring\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 系统监控</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:20px\">\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"cpuUsage\">0%</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">CPU 使用率</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"memoryUsage\">0%</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">内存使用率</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"diskUsage\">0%</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">磁盘使用率</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--text)\" id=\"uptimeDisplay\">0h</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">运行时间</div>\n</div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"loadSystemMetrics()\">🔄 刷新指标</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 性能指标</h4>\n<div id=\"performanceMetrics\" style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 告警列表</h4>\n<div id=\"alertsList\" style=\"max-height:300px;overflow-y:auto\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> 链路追踪</h4>\n<div id=\"tracesList\" style=\"max-height:300px;overflow-y:auto\"></div>\n</div>\n</div></div></div></div>\n<!-- 任务队列页 -->\n<div id=\"page-tasks\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 任务队列</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:20px\">\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"pendingTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">待处理</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"runningTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">运行中</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"completedTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">已完成</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"failedTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">失败</div>\n</div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"loadTaskQueue()\">🔄 刷新队列</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 任务列表</h4>\n<div id=\"tasksList\" style=\"max-height:400px;overflow-y:auto\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⏰</span> 定时任务</h4>\n<div id=\"scheduledJobs\" style=\"max-height:300px;overflow-y:auto\"></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- 第三方集成页 -->\n<div id=\"page-integrations\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔗</span> 第三方集成</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:20px\">连接 Slack、飞书等平台,让 AI 助手无处不在</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> Slack 集成</h4>\n<div class=\"form-group\"><label>Bot Token</label><input type=\"password\" id=\"slackToken\" placeholder=\"xoxb-...\" onchange=\"saveIntegration('slack')\"></div>\n<div class=\"form-group\"><label>Signing Secret</label><input type=\"password\" id=\"slackSecret\" placeholder=\"签名密钥\" onchange=\"saveIntegration('slack')\"></div>\n<div class=\"form-group\"><label>Webhook URL</label><div style=\"display:flex;gap:8px\"><input type=\"text\" value=\"http://localhost:8000/api/integrations/slack/webhook\" readonly style=\"flex:1;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText(this.previousElementSibling.value)\">📋</button></div></div>\n<div style=\"display:flex;gap:12px;margin-top:16px\">\n<button class=\"btn btn-primary\" onclick=\"testSlackIntegration()\">🧪 测试连接</button>\n<button class=\"btn btn-ghost\" onclick=\"window.open('https://api.slack.com/apps','_blank')\">📖 创建 Slack App</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐦</span> 飞书集成</h4>\n<div class=\"form-group\"><label>App ID</label><input type=\"text\" id=\"feishuAppId\" placeholder=\"cli_...\" onchange=\"saveIntegration('feishu')\"></div>\n<div class=\"form-group\"><label>App Secret</label><input type=\"password\" id=\"feishuSecret\" placeholder=\"应用密钥\" onchange=\"saveIntegration('feishu')\"></div>\n<div class=\"form-group\"><label>Webhook URL</label><div style=\"display:flex;gap:8px\"><input type=\"text\" value=\"http://localhost:8000/api/integrations/feishu/webhook\" readonly style=\"flex:1;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText(this.previousElementSibling.value)\">📋</button></div></div>\n<div style=\"display:flex;gap:12px;margin-top:16px\">\n<button class=\"btn btn-primary\" onclick=\"testFeishuIntegration()\">🧪 测试连接</button>\n<button class=\"btn btn-ghost\" onclick=\"window.open('https://open.feishu.cn/app','_blank')\">📖 创建飞书应用</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> Webhook 通知</h4>\n<div class=\"form-group\"><label>通知 URL</label><input type=\"text\" id=\"webhookUrl\" placeholder=\"https://your-server.com/webhook\" onchange=\"saveIntegration('webhook')\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">新消息通知</div><label class=\"switch\"><input type=\"checkbox\" id=\"webhookNewMsg\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">错误通知</div><label class=\"switch\"><input type=\"checkbox\" id=\"webhookError\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🎛️</span> 灰度发布</h4>\n<div id=\"featureFlagsList\"></div>\n<button class=\"btn btn-ghost\" onclick=\"loadFeatureFlags()\" style=\"margin-top:12px\">🔄 刷新</button>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Agent 工作流页 -->\n<div id=\"page-workflows\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🤖</span> Agent 工作流</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建多步骤自动化任务,让 AI 按流程完成复杂工作</p>\n<div id=\"workflowTemplates\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👥</span> 多 Agent 协作</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">多个 AI Agent 协同完成复杂任务</p>\n<div class=\"form-group\"><label>任务描述</label><textarea id=\"multiAgentTask\" rows=\"3\" placeholder=\"描述你需要完成的任务...\"></textarea></div>\n<div class=\"form-group\"><label>选择 Agent</label>\n<div id=\"agentCheckboxes\" style=\"display:flex;flex-wrap:wrap;gap:12px\"></div>\n</div>\n<div class=\"form-group\"><label>协作模式</label>\n<select id=\"agentMode\" style=\"width:200px;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\">\n<option value=\"sequential\">顺序执行</option>\n<option value=\"parallel\">并行执行</option>\n<option value=\"debate\">辩论模式</option>\n</select>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runMultiAgent()\">🚀 开始协作</button>\n<button class=\"btn btn-ghost\" onclick=\"showCreateAgentModal()\" style=\"margin-left:8px\">+ 创建 Agent</button>\n</div>\n<div class=\"settings-section\" id=\"multiAgentResults\" style=\"display:none\">\n<h4><span>📋</span> 协作结果</h4>\n<div id=\"multiAgentResultsContent\"></div>\n</div>\n<div class=\"settings-section\" id=\"workflowRunner\" style=\"display:none\">\n<h4><span>▶️</span> 运行工作流</h4>\n<div id=\"workflowInputs\"></div>\n<button class=\"btn btn-primary\" onclick=\"executeWorkflow()\">🚀 执行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('workflowRunner').style.display='none'\">取消</button>\n</div>\n<div class=\"settings-section\" id=\"workflowResults\" style=\"display:none\">\n<h4><span>📋</span> 执行结果</h4>\n<div id=\"workflowResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 代码运行器页 -->\n<div id=\"page-code-runner\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>▶️</span> 代码运行器</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">在线运行 Python / JavaScript 代码</p>\n<div class=\"form-group\">\n<label>语言</label>\n<select id=\"codeLanguage\" style=\"width:150px\">\n<option value=\"python\">Python</option>\n<option value=\"javascript\">JavaScript</option>\n</select>\n</div>\n<div class=\"form-group\">\n<label>代码</label>\n<textarea id=\"codeInput\" rows=\"12\" style=\"font-family:monospace;font-size:13px\" placeholder=\"# 输入代码...\nprint('Hello, World!')\"></textarea>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-primary\" onclick=\"runCode()\">▶️ 运行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('codeInput').value=''\">清空</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 输出结果</h4>\n<pre id=\"codeOutput\" style=\"background:var(--bg);padding:16px;border-radius:8px;min-height:100px;font-family:monospace;font-size:13px;white-space:pre-wrap\">等待运行...</pre>\n</div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>系统状态</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + H</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量选择模式</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + B</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量导出</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>搜索当前对话</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + F</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换主题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + D</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<!-- 登录弹窗已移除 -->\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();if(n.dataset.page==='workflows')loadWorkflowTemplates();if(n.dataset.page==='traces')loadTraces();if(n.dataset.page==='integrations')loadFeatureFlags();if(n.dataset.page==='rag')loadRAGKnowledgeBases();if(n.dataset.page==='billing'){loadBillingPlans();loadSubscription();loadUsageStats();loadInvoices()}if(n.dataset.page==='rbac'){loadMyPermissions();loadRoles()}if(n.dataset.page==='local-models')loadOllamaModels();if(n.dataset.page==='workflows')loadAgents();if(n.dataset.page==='audit')loadAuditLogs();if(n.dataset.page==='security')loadSecurityStatus();if(n.dataset.page==='monitoring'){loadSystemMetrics();loadAlerts();loadTraces()}if(n.dataset.page==='tasks')loadTaskQueue();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{\n// 先显示置顶的对话\nvar pinnedChats=chats.filter(function(c){return c.pinned});\nvar normalChats=chats.filter(function(c){return !c.pinned&&!c.archived});\nif(pinnedChats.length>0){html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2)\">📌 置顶</div>';pinnedChats.forEach(function(c){html+=renderChatItem(c)})}\nif(normalChats.length>0){if(pinnedChats.length>0)html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2);margin-top:8px\">💬 对话</div>';normalChats.forEach(function(c){html+=renderChatItem(c)})}}$('chatList').innerHTML=html}\nfunction renderChatItem(c){var isSelected=(typeof selectedChats!=='undefined'&&selectedChats.indexOf(c.id)>=0);var selected=isSelected?'border:2px solid var(--accent);':'';var checkbox=(typeof batchMode!=='undefined'&&batchMode)?'<input type=\"checkbox\" '+(isSelected?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';var pinIcon=c.pinned?'📌':'💬';return'<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" style=\"'+selected+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">'+pinIcon+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"favoriteMessageByIndex('+i+')\" title=\"收藏\">❤️</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll();showQuickReplies()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var providerName=p?p.id:'custom';var payload={provider:providerName,model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:'',time:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);chat.messages[chat.messages.length-1].time=elapsed+'s';saveChats();renderMessages();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]'){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);chat.messages[chat.messages.length-1].time=elapsed+'s';return}try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;var currentElapsed=((Date.now()-chatStartTime)/1000).toFixed(1);chat.messages[chat.messages.length-1].time=currentElapsed+'s';renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var chat=chats.find(function(c){return c.id===id});var pinText=chat&&chat.pinned?'📌 取消置顶':'📌 置顶';var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"togglePinChat(\\''+id+'\\')\">'+pinText+'</div><div onclick=\"archiveChat(\\''+id+'\\')\">📦 归档</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction togglePinChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.pinned=!chat.pinned;saveChats();renderChats();showToast(chat.pinned?'已置顶':'已取消置顶');if(authToken){api('/api/conversations/'+id+'/pin',{method:'POST'}).catch(function(){})}}\nfunction archiveChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.archived=true;chats=chats.filter(function(c){return c.id!==id});saveChats();renderChats();showToast('已归档');if(authToken){api('/api/conversations/'+id+'/archive',{method:'POST'}).catch(function(){})}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.documentElement.setAttribute('data-theme',mode);localStorage.setItem('theme',mode);document.querySelectorAll('.theme-btn').forEach(function(btn){btn.classList.remove('active')});event.target.classList.add('active')}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Agent 工作流\nvar workflowTemplates=[];\nvar currentWorkflow=null;\nfunction loadWorkflowTemplates(){api('/api/workflows/templates').then(function(data){workflowTemplates=data;renderWorkflowTemplates()}).catch(function(e){console.error('加载工作流失败:',e)})}\nfunction renderWorkflowTemplates(){var html=workflowTemplates.map(function(w){return'<div style=\"background:var(--bg);border-radius:12px;padding:20px;cursor:pointer\" onclick=\"selectWorkflow(\\''+w.id+'\\')\"><div style=\"display:flex;align-items:center;gap:12px;margin-bottom:12px\"><span style=\"font-size:24px\">🤖</span><div><strong>'+w.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+w.steps.length+' 个步骤</div></div></div><p style=\"font-size:13px;color:var(--text2);line-height:1.5\">'+w.description+'</p></div>'}).join('');$('workflowTemplates').innerHTML=html||'<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无工作流模板</div>'}\nfunction selectWorkflow(id){currentWorkflow=workflowTemplates.find(function(w){return w.id===id});if(!currentWorkflow)return;var inputs=[];currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')&&inputs.indexOf(key)===-1)inputs.push(key)})}});var html=inputs.map(function(key){return'<div class=\"form-group\"><label>'+key+'</label><textarea id=\"wf_'+key+'\" rows=\"3\" placeholder=\"输入 '+key+'\"></textarea></div>'}).join('');$('workflowInputs').innerHTML='<h5 style=\"margin-bottom:16px\">'+currentWorkflow.name+'</h5>'+html;$('workflowRunner').style.display='block';$('workflowResults').style.display='none'}\nfunction executeWorkflow(){if(!currentWorkflow){alert('请先选择工作流');return}var inputData={};currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')){var el=$('wf_'+key);if(el)inputData[key]=el.value}})}});$('workflowResultsContent').innerHTML='<div style=\"text-align:center;padding:40px\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px;color:var(--text2)\">正在执行工作流...</p></div>';$('workflowResults').style.display='block';api('/api/workflows/run',{method:'POST',body:JSON.stringify({name:currentWorkflow.name,steps:currentWorkflow.steps,input_data:inputData})}).then(function(data){var html='';for(var key in data.results){html+='<div style=\"background:var(--bg);border-radius:10px;padding:16px;margin-bottom:12px\"><div style=\"font-weight:600;margin-bottom:8px;color:var(--accent)\">'+key+'</div><div style=\"font-size:14px;line-height:1.6;white-space:pre-wrap\">'+data.results[key]+'</div></div>'}$('workflowResultsContent').innerHTML=html}).catch(function(e){$('workflowResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">执行失败: '+e.message+'</div>'})}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';if(typeof selectedCompareModels==='undefined')selectedCompareModels=[];providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.some(function(x){return x.id===id})?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});var el=$('compareModelList');if(el)el.innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// GitHub 登录\nfunction loginWithGithub(){window.location.href='/api/auth/github'}\n// 2FA 设置\nfunction setup2FA(){if(!authToken){alert('请先登录');return}api('/api/auth/2fa/setup',{method:'POST'}).then(function(data){var html='<div style=\"text-align:center\"><img src=\"'+data.qr_code+'\" style=\"width:200px;height:200px;border-radius:8px\"><p style=\"margin:16px 0;color:var(--text2);font-size:13px\">使用 Google Authenticator 扫描二维码</p><div class=\"form-group\"><label>输入6位验证码确认</label><input type=\"text\" id=\"verify2FACode\" placeholder=\"000000\" maxlength=\"6\" style=\"text-align:center;font-size:20px;letter-spacing:8px\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"verify2FA()\">确认启用</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'2faModal\\')\">取消</button></div></div>';showCustomModal('设置双因素认证',html,'2faModal')}).catch(function(e){alert('设置失败: '+e.message)})}\nfunction verify2FA(){var code=$('verify2FACode').value.trim();if(code.length!==6){alert('请输入6位验证码');return}api('/api/auth/2fa/verify',{method:'POST',body:JSON.stringify({code:code})}).then(function(data){closeModal('2faModal');$('2faStatus').textContent='已启用';$('2faStatus').style.color='var(--success)';$('2faBtn').textContent='禁用';$('2faBtn').onclick=disable2FA;showToast('2FA 已启用')}).catch(function(e){alert('验证失败: '+e.message)})}\nfunction disable2FA(){var code=prompt('输入6位验证码以禁用 2FA:');if(!code)return;api('/api/auth/2fa/disable',{method:'POST',body:JSON.stringify({code:code})}).then(function(){$('2faStatus').textContent='未启用';$('2faStatus').style.color='var(--text2)';$('2faBtn').textContent='设置';$('2faBtn').onclick=setup2FA;showToast('2FA 已禁用')}).catch(function(e){alert('禁用失败: '+e.message)})}\nfunction showChangePasswordModal(){var html='<div class=\"form-group\"><label>当前密码</label><input type=\"password\" id=\"oldPassword\"></div><div class=\"form-group\"><label>新密码</label><input type=\"password\" id=\"newPassword\"></div><div class=\"form-group\"><label>确认新密码</label><input type=\"password\" id=\"confirmPassword\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"changePassword()\">修改</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pwdModal\\')\">取消</button></div>';showCustomModal('修改密码',html,'pwdModal')}\nfunction changePassword(){var oldPwd=$('oldPassword').value,newPwd=$('newPassword').value,confirmPwd=$('confirmPassword').value;if(!oldPwd||!newPwd){alert('请填写密码');return}if(newPwd!==confirmPwd){alert('两次密码不一致');return}alert('密码修改功能开发中')}\n// 检查 URL 中的 token(OAuth 回调)\n(function(){var params=new URLSearchParams(window.location.search);var token=params.get('token');if(token){localStorage.setItem('token',token);authToken=token;window.history.replaceState({},document.title,'/');checkAuth()}})();\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\n// 代码运行器\nfunction runCode(){var code=$('codeInput').value;var lang=$('codeLanguage').value;if(!code.trim()){alert('请输入代码');return}$('codeOutput').textContent='运行中...';$('codeOutput').style.color='var(--text2)';api('/api/code/run',{method:'POST',body:JSON.stringify({code:code,language:lang,timeout:5})}).then(function(data){if(data.success){$('codeOutput').textContent=data.output||'(无输出)';$('codeOutput').style.color='var(--success)'}else{$('codeOutput').textContent='错误: '+(data.error||'未知错误')+'\\n'+data.output;$('codeOutput').style.color='var(--error)'}}).catch(function(e){$('codeOutput').textContent='请求失败: '+e.message;$('codeOutput').style.color='var(--error)'})}\n// 思维导图\nfunction generateMindmap(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}showToast('正在生成思维导图...');api('/api/mindmap/generate',{method:'POST',body:JSON.stringify({messages:chat.messages,title:chat.title})}).then(function(data){renderMindmap(data.nodes)}).catch(function(e){alert('生成失败: '+e.message)})}\nfunction renderMindmap(nodes){var html='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.8);z-index:2000;display:flex;align-items:center;justify-content:center\" onclick=\"if(event.target===this)this.remove()\"><div style=\"background:var(--bg2);border-radius:16px;padding:24px;max-width:800px;max-height:80vh;overflow:auto\"><h3 style=\"margin-bottom:16px\">🧠 思维导图</h3><div id=\"mindmapContent\" style=\"padding:20px\"></div><button class=\"btn btn-ghost\" onclick=\"this.parentElement.parentElement.remove()\">关闭</button></div></div>';document.body.insertAdjacentHTML('beforeend',html);var content='';function renderNode(node,level){var indent=level*24;content+='<div style=\"margin-left:'+indent+'px;padding:8px 12px;margin-bottom:4px;background:var(--bg'+(level>0?'3':'')+');border-radius:6px;border-left:3px solid var(--accent)\">'+(level>0?'├─ ':'')+node.label+'</div>';if(node.children){node.children.forEach(function(c){renderNode(c,level+1)})}}if(nodes&&nodes.length)renderNode(nodes[0],0);$('mindmapContent').innerHTML=content||'<p style=\"color:var(--text2)\">无法生成思维导图</p>'}\n// 保存对话为模板\nfunction saveAsTemplate(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}var name=prompt('模板名称:',chat.title);if(!name)return;api('/api/chat-templates',{method:'POST',body:JSON.stringify({name:name,messages:chat.messages})}).then(function(){showToast('已保存为模板')}).catch(function(e){alert('保存失败: '+e.message)})}\n// 用量配额\nfunction loadQuota(){api('/api/quota').then(function(data){var html='<div style=\"margin-bottom:16px\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Token 使用量</span><span>'+formatNumber(data.tokens_used)+' / '+formatNumber(data.tokens_limit)+'</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;overflow:hidden\"><div style=\"background:var(--accent);height:100%;width:'+data.usage_percent+'%\"></div></div></div><p style=\"font-size:12px;color:var(--text2)\">当前套餐: '+data.plan+'</p>';if($('quotaInfo'))$('quotaInfo').innerHTML=html}).catch(function(e){console.error(e)})}\n// PWA 注册\nif('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js').then(function(reg){console.log('SW registered');if('Notification' in window&&Notification.permission==='default'){Notification.requestPermission()}}).catch(function(e){console.error('SW failed:',e)})}\n// 图片生成\nfunction generateImage(){var prompt=prompt('输入图片描述:');if(!prompt)return;showToast('正在生成图片...');api('/api/images/generate',{method:'POST',body:JSON.stringify({prompt:prompt})}).then(function(data){var img='<img src=\"'+data.url+'\" style=\"max-width:100%;border-radius:8px\">';var chat=chats.find(function(c){return c.id===currentChatId});if(chat){chat.messages.push({role:'assistant',content:'![生成的图片]('+data.url+')\\n\\n'+data.revised_prompt});saveChats();renderMessages()}showToast('图片已生成')}).catch(function(e){alert('生成失败: '+e.message)})}\n// TTS 语音合成\nfunction speakText(text){api('/api/audio/tts',{method:'POST',body:JSON.stringify({text:text,voice:'alloy'})}).then(function(data){var audio=new Audio(data.audio);audio.play();showToast('正在播放')}).catch(function(e){if('speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(text);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('TTS 失败: '+e.message)}})}\n// 内容过滤\nfunction filterContent(text){return api('/api/content/filter',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data})}\n// 数据脱敏\nfunction maskData(text){return api('/api/data/mask',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data.masked})}\n// 备份\nfunction createBackup(){api('/api/backup',{method:'POST'}).then(function(data){showToast('备份已创建: '+data.path)}).catch(function(e){alert('备份失败: '+e.message)})}\n// 离线检测\nwindow.addEventListener('online',function(){showToast('网络已恢复')});\nwindow.addEventListener('offline',function(){showToast('网络已断开,部分功能不可用')});\n\n// ========== 性能监控面板 ==========\nfunction showHealthDashboard(){\napi('/api/health/detailed').then(function(data){\nvar html='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">CPU 使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.cpu_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.cpu_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">内存使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.memory_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.memory_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">磁盘使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.disk_percent>90?'var(--error)':'var(--success)')+'\">'+data.system.disk_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">数据库延迟</div><div style=\"font-size:24px;font-weight:600;color:'+(data.components.database.latency_ms>100?'var(--warning)':'var(--success)')+'\">'+data.components.database.latency_ms+'ms</div></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:10px\">';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>缓存</span><span>'+data.components.cache.size+'/'+data.components.cache.max_size+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Redis</span><span style=\"color:'+(data.components.redis.status==='healthy'?'var(--success)':'var(--warning)')+'\">'+data.components.redis.status+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between\"><span>待处理任务</span><span>'+data.components.task_queue.pending_tasks+'</span></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;text-align:center;font-size:12px;color:var(--text2)\">版本 '+data.version+' · 运行时间 '+formatUptime(data.uptime_seconds)+'</div>';\nshowCustomModal('🖥️ 系统状态',html,'healthModal')\n}).catch(function(e){alert('获取状态失败: '+e.message)})}\nfunction formatUptime(seconds){var h=Math.floor(seconds/3600);var m=Math.floor((seconds%3600)/60);return h+'小时'+m+'分钟'}\n\n// ========== 批量操作 ==========\nvar batchMode=false;\nvar selectedChats=[];\nfunction toggleBatchMode(){batchMode=!batchMode;selectedChats=[];if(batchMode){$('batchActions').style.display='flex';showToast('已进入批量选择模式')}else{$('batchActions').style.display='none'}renderChats()}\nfunction toggleChatSelection(id,e){if(!batchMode)return;e.stopPropagation();var idx=selectedChats.indexOf(id);if(idx>=0){selectedChats.splice(idx,1)}else{selectedChats.push(id)}renderChats();$('selectedCount').textContent=selectedChats.length}\nfunction batchDeleteChats(){if(selectedChats.length===0){alert('请先选择对话');return}if(!confirm('确定删除 '+selectedChats.length+' 个对话?'))return;api('/api/conversations/batch-delete',{method:'POST',body:JSON.stringify({ids:selectedChats})}).then(function(data){showToast('已删除 '+data.deleted+' 个对话');selectedChats=[];batchMode=false;$('batchActions').style.display='none';loadChats()}).catch(function(e){alert('删除失败: '+e.message)})}\nfunction batchExportChats(){if(selectedChats.length===0){alert('请先选择对话');return}api('/api/messages/batch-export',{method:'POST',body:JSON.stringify({conversation_ids:selectedChats,format:'json'})}).then(function(data){var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='conversations_export.json';a.click();showToast('已导出 '+data.count+' 个对话')}).catch(function(e){alert('导出失败: '+e.message)})}\n\n// ========== 数据库优化 ==========\nfunction optimizeDatabase(){if(!confirm('确定要优化数据库?这将清理过期数据。'))return;showToast('正在优化...');api('/api/admin/optimize-db',{method:'POST'}).then(function(data){showToast(data.message)}).catch(function(e){alert('优化失败: '+e.message)})}\n\n// ========== 快捷键增强 ==========\ndocument.addEventListener('keydown',function(e){\nif(e.ctrlKey&&e.key==='h'){e.preventDefault();showHealthDashboard()}\nif(e.ctrlKey&&e.key==='b'){e.preventDefault();toggleBatchMode()}\nif(e.ctrlKey&&e.shiftKey&&e.key==='E'){e.preventDefault();batchExportChats()}\nif(e.ctrlKey&&e.key==='f'){e.preventDefault();searchInCurrentChat()}\nif(e.ctrlKey&&e.key==='/'||e.key==='?'){e.preventDefault();showHotkeyHelp()}\n});\n\n// ========== 性能优化:虚拟滚动 ==========\nfunction renderChatListVirtual(){\nvar container=$('chatList');\nvar itemHeight=60;\nvar visibleCount=Math.ceil(container.clientHeight/itemHeight)+2;\nvar scrollTop=container.scrollTop;\nvar startIndex=Math.floor(scrollTop/itemHeight);\nvar endIndex=Math.min(startIndex+visibleCount,chats.length);\nvar html='<div style=\"height:'+(startIndex*itemHeight)+'px\"></div>';\nfor(var i=startIndex;i<endIndex;i++){\nvar c=chats[i];\nvar active=c.id===currentChatId?'active':'';\nvar selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';\nvar checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';\nhtml+='<div class=\"sidebar-item '+active+'\" style=\"'+selected+'\" onclick=\"loadChat(\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+c.title+'</div><div class=\"sidebar-item-desc\">'+(c.messages.length||0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" style=\"opacity:0\" onclick=\"deleteChat(\\''+c.id+'\\',event)\">🗑️</button></div>'\n}\nhtml+='<div style=\"height:'+((chats.length-endIndex)*itemHeight)+'px\"></div>';\ncontainer.innerHTML=html}\n\n// ========== 请求重试机制 ==========\nasync function apiWithRetry(url,options,maxRetries=3){\nfor(var i=0;i<maxRetries;i++){\ntry{return await api(url,options)}\ncatch(e){\nif(i===maxRetries-1)throw e;\nawait new Promise(function(r){setTimeout(r,1000*(i+1))});\nconsole.log('Retrying request...',i+1)\n}}}\n\n// ========== 消息队列(离线支持) ==========\nvar offlineQueue=JSON.parse(localStorage.getItem('offlineQueue')||'[]');\nfunction queueOfflineMessage(msg){offlineQueue.push({msg:msg,time:Date.now()});localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))}\nfunction processOfflineQueue(){if(offlineQueue.length===0)return;showToast('正在发送离线消息...');var msg=offlineQueue.shift();localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue));sendMessageInternal(msg.msg).then(function(){processOfflineQueue()}).catch(function(){offlineQueue.unshift(msg);localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))})}\nwindow.addEventListener('online',processOfflineQueue);\n\n// ========== 智能预加载 ==========\nfunction preloadNextChat(){\nvar currentIdx=chats.findIndex(function(c){return c.id===currentChatId});\nif(currentIdx>=0&&currentIdx<chats.length-1){\nvar nextChat=chats[currentIdx+1];\nif(!nextChat.messages||nextChat.messages.length===0){\napi('/api/conversations/'+nextChat.id+'/messages').then(function(msgs){nextChat.messages=msgs})}}}\n\n// ========== 自动保存草稿 ==========\nvar draftTimer=null;\nfunction saveDraft(){var input=$('chatInput').value;if(input&&currentChatId){localStorage.setItem('draft_'+currentChatId,input)}}\nfunction loadDraft(){if(currentChatId){var draft=localStorage.getItem('draft_'+currentChatId);if(draft)$('chatInput').value=draft}}\nfunction clearDraft(){if(currentChatId)localStorage.removeItem('draft_'+currentChatId)}\n$('chatInput').addEventListener('input',function(){clearTimeout(draftTimer);draftTimer=setTimeout(saveDraft,1000)});\n\n// ========== 消息搜索增强 ==========\nfunction searchInCurrentChat(){var q=prompt('在当前对话中搜索:');if(!q)return;var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages)return;var results=chat.messages.filter(function(m){return m.content&&m.content.toLowerCase().includes(q.toLowerCase())});if(results.length===0){alert('未找到匹配消息');return}var html='<div style=\"max-height:400px;overflow-y:auto\">';results.forEach(function(m,i){html+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:4px\">'+(m.role==='user'?'👤 用户':'🤖 助手')+'</div><div style=\"font-size:14px\">'+m.content.slice(0,200)+(m.content.length>200?'...':'')+'</div></div>'});html+='</div>';showCustomModal('搜索结果 ('+results.length+')',html,'searchResultModal')}\n\n// ========== 快速回复 ==========\nvar quickReplies=[\n{id:'continue',text:'继续',prompt:'请继续'},\n{id:'explain',text:'解释',prompt:'请详细解释一下'},\n{id:'example',text:'举例',prompt:'请举个例子'},\n{id:'simplify',text:'简化',prompt:'请用更简单的语言解释'},\n{id:'code',text:'代码',prompt:'请给出代码示例'},\n{id:'summary',text:'总结',prompt:'请总结一下要点'}\n];\nfunction showQuickReplies(){\nvar el=$('quickReplies');\nif(!el)return;\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages||chat.messages.length===0){el.style.display='none';return}\nvar lastMsg=chat.messages[chat.messages.length-1];\nif(lastMsg.role!=='assistant'){el.style.display='none';return}\nif(typeof quickReplies==='undefined'||!quickReplies){el.style.display='none';return}\nvar html=quickReplies.map(function(r){return'<button class=\"btn btn-ghost btn-sm\" onclick=\"sendQuickReply(\\''+r.prompt+'\\')\">'+r.text+'</button>'}).join('');\nel.innerHTML=html;\nel.style.display='flex'}\nfunction sendQuickReply(prompt){$('chatInput').value=prompt;sendMessage()}\n\n// ========== 数据导入导出 ==========\nfunction exportAllData(){\nif(!authToken){alert('请先登录');return}\nshowToast('正在导出数据...');\napi('/api/data/export-all',{method:'POST'}).then(function(data){\nvar blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='ai_hub_backup_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})}\n\nfunction importAllData(){\nif(!authToken){alert('请先登录');return}\nvar input=document.createElement('input');\ninput.type='file';\ninput.accept='.json';\ninput.onchange=function(e){\nvar file=e.target.files[0];\nif(!file)return;\nvar reader=new FileReader();\nreader.onload=function(ev){\ntry{\nvar data=JSON.parse(ev.target.result);\nif(!confirm('确定要导入数据?这将添加 '+\n(data.conversations?data.conversations.length:0)+' 个对话、'+\n(data.notes?data.notes.length:0)+' 个笔记'))return;\napi('/api/data/import',{method:'POST',body:JSON.stringify(data)}).then(function(result){\nshowToast('导入完成: '+result.imported.conversations+' 对话, '+result.imported.notes+' 笔记');\nloadChats()\n}).catch(function(e){alert('导入失败: '+e.message)})\n}catch(e){alert('文件格式错误')}};\nreader.readAsText(file)};\ninput.click()}\n\n// ========== 智能推荐 ==========\nfunction loadRecommendations(){\napi('/api/recommendations').then(function(data){\nif(data.features&&data.features.length>0){\nvar html='<div style=\"padding:16px;background:var(--bg3);border-radius:10px;margin-bottom:16px\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:12px\">💡 推荐功能</div><div style=\"display:flex;gap:12px;flex-wrap:wrap\">';\ndata.features.forEach(function(f){\nhtml+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;cursor:pointer;flex:1;min-width:150px\" onclick=\"showFeatureGuide(\\''+f.name+'\\')\"><span style=\"font-size:20px\">'+f.icon+'</span><div style=\"font-size:14px;font-weight:500;margin-top:8px\">'+f.name+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+f.desc+'</div></div>'});\nhtml+='</div></div>';\nvar container=$('chatMessages');\nif(container&&container.querySelector('.empty-state')){\ncontainer.innerHTML=html+container.innerHTML}}\n}).catch(function(){})}\nfunction showFeatureGuide(name){\nvar guides={\n'知识库':'点击左侧导航的\"知识库\",创建知识库并上传文档,AI 将基于您的资料回答问题。',\n'团队协作':'点击左侧导航的\"团队空间\",创建团队并邀请成员,共享对话和资源。'\n};\nalert(guides[name]||'功能介绍开发中')}\n\n// ========== 收藏消息 ==========\nfunction favoriteMessage(content){\nif(!authToken){alert('请先登录');return}\napi('/api/messages/favorite',{method:'POST',body:JSON.stringify({\nconversation_id:currentChatId,\ncontent:content\n})}).then(function(){showToast('已收藏到记忆')}).catch(function(e){alert('收藏失败: '+e.message)})}\nfunction favoriteMessageByIndex(index){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages[index])return;\nfavoriteMessage(chat.messages[index].content)}\n\n// ========== 使用分析 ==========\nfunction showUsageAnalytics(){\napi('/api/analytics/usage?days=30').then(function(data){\nvar html='<div style=\"margin-bottom:20px\"><h4 style=\"margin-bottom:12px\">📊 30天使用趋势</h4>';\nif(data.daily_usage.length>0){\nvar maxCalls=Math.max.apply(null,data.daily_usage.map(function(d){return d.calls}));\nhtml+='<div style=\"display:flex;align-items:flex-end;gap:4px;height:100px\">';\ndata.daily_usage.forEach(function(d){\nvar height=Math.max(5,(d.calls/maxCalls)*100);\nhtml+='<div style=\"flex:1;background:var(--accent);border-radius:2px 2px 0 0;height:'+height+'px\" title=\"'+d.day+': '+d.calls+'次\"></div>'});\nhtml+='</div>'}\nhtml+='</div>';\nhtml+='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">总调用次数</div><div style=\"font-size:24px;font-weight:600\">'+data.total_calls+'</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">错误率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.error_rate>5?'var(--error)':'var(--success)')+'\">'+data.error_rate+'%</div></div>';\nhtml+='</div>';\nshowCustomModal('📈 使用分析',html,'analyticsModal')\n}).catch(function(e){alert('获取分析失败: '+e.message)})}\n\n// ========== 第三方集成 ==========\nfunction saveIntegration(type){\nvar data={};\nif(type==='slack'){\ndata={slack_token:$('slackToken').value,slack_secret:$('slackSecret').value}\n}else if(type==='feishu'){\ndata={feishu_app_id:$('feishuAppId').value,feishu_secret:$('feishuSecret').value}\n}else if(type==='webhook'){\ndata={webhook_url:$('webhookUrl').value,webhook_new_msg:$('webhookNewMsg').checked,webhook_error:$('webhookError').checked}\n}\nlocalStorage.setItem('integration_'+type,JSON.stringify(data));\nshowToast('配置已保存')}\n\nfunction loadIntegrations(){\ntry{\nvar slack=JSON.parse(localStorage.getItem('integration_slack')||'{}');\nif(slack.slack_token)$('slackToken').value=slack.slack_token;\nif(slack.slack_secret)$('slackSecret').value=slack.slack_secret;\nvar feishu=JSON.parse(localStorage.getItem('integration_feishu')||'{}');\nif(feishu.feishu_app_id)$('feishuAppId').value=feishu.feishu_app_id;\nif(feishu.feishu_secret)$('feishuSecret').value=feishu.feishu_secret;\nvar webhook=JSON.parse(localStorage.getItem('integration_webhook')||'{}');\nif(webhook.webhook_url)$('webhookUrl').value=webhook.webhook_url;\nif(webhook.webhook_new_msg)$('webhookNewMsg').checked=true;\nif(webhook.webhook_error)$('webhookError').checked=true;\n}catch(e){}}\n\nfunction testSlackIntegration(){\nshowToast('测试 Slack 连接...');\napi('/api/integrations/slack/send',{method:'POST',body:JSON.stringify({channel:'#general',text:'AI Hub 测试消息'})}).then(function(data){\nif(data.ok){showToast('Slack 连接成功!')}else{alert('连接失败: '+(data.error||'未知错误'))}\n}).catch(function(e){alert('连接失败: '+e.message)})}\n\nfunction testFeishuIntegration(){\nshowToast('测试飞书连接...');\napi('/api/integrations/feishu/send',{method:'POST',body:JSON.stringify({chat_id:'test',text:'AI Hub 测试消息'})}).then(function(data){\nif(data.code===0){showToast('飞书连接成功!')}else{alert('连接失败: '+(data.msg||'未知错误'))}\n}).catch(function(e){alert('连接失败: '+e.message)})}\n\n// ========== 灰度发布 ==========\nfunction loadFeatureFlags(){\napi('/api/features/all').then(function(data){\nvar html='';\nfor(var name in data){\nvar flag=data[name];\nhtml+='<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\">';\nhtml+='<div><strong>'+name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">灰度比例: '+flag.percentage+'% · 白名单用户: '+(flag.users?flag.users.length:0)+'</div></div>';\nhtml+='<label class=\"switch\"><input type=\"checkbox\" '+(flag.enabled?'checked':'')+' onchange=\"toggleFeatureFlag(\\''+name+'\\',this.checked)\"><span class=\"switch-slider\"></span></label>';\nhtml+='</div>'}\n$('featureFlagsList').innerHTML=html||'<p style=\"color:var(--text2)\">暂无功能开关</p>'\n}).catch(function(e){$('featureFlagsList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction toggleFeatureFlag(name,enabled){\napi('/api/features/'+name,{method:'POST',body:JSON.stringify({enabled:enabled})}).then(function(){\nshowToast(name+(enabled?' 已启用':' 已禁用'))\n}).catch(function(e){alert('操作失败: '+e.message)})}\n\nfunction updateFeatureFlagPercentage(name,percentage){\napi('/api/features/'+name,{method:'POST',body:JSON.stringify({percentage:parseInt(percentage)})}).then(function(){\nshowToast('灰度比例已更新')\n}).catch(function(e){alert('操作失败: '+e.message)})}\n\n// ========== 链路追踪 ==========\nfunction loadTraces(){\napi('/api/traces?limit=50').then(function(data){\nif(data.length===0){$('tracesList').innerHTML='<p style=\"color:var(--text2)\">暂无追踪记录</p>';return}\nvar html='<table style=\"width:100%;border-collapse:collapse;font-size:13px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">ID</th><th style=\"padding:10px\">名称</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">Spans</th></tr>';\ndata.forEach(function(t){\nhtml+='<tr style=\"border-top:1px solid var(--border);cursor:pointer\" onclick=\"showTraceDetail(\\''+t.id+'\\')\">';\nhtml+='<td style=\"padding:10px;font-family:monospace\">'+t.id+'</td>';\nhtml+='<td style=\"padding:10px\">'+t.name+'</td>';\nhtml+='<td style=\"padding:10px;text-align:right\">'+(t.total_duration?(t.total_duration*1000).toFixed(0)+'ms':'-')+'</td>';\nhtml+='<td style=\"padding:10px\">'+(t.spans?t.spans.length:0)+'</td>';\nhtml+='</tr>'});\nhtml+='</table>';\n$('tracesList').innerHTML=html\n}).catch(function(e){$('tracesList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction showTraceDetail(traceId){\napi('/api/traces/'+traceId).then(function(data){\nvar html='<div style=\"margin-bottom:16px\"><strong>Trace ID:</strong> '+data.id+'<br><strong>名称:</strong> '+data.name+'<br><strong>总耗时:</strong> '+(data.total_duration?(data.total_duration*1000).toFixed(0)+'ms':'-')+'</div>';\nif(data.spans&&data.spans.length>0){\nhtml+='<h4 style=\"margin-bottom:12px\">Spans</h4>';\ndata.spans.forEach(function(s,i){\nvar width=Math.min(100,s.duration*100);\nhtml+='<div style=\"margin-bottom:8px\"><div style=\"display:flex;justify-content:space-between;font-size:13px\"><span>'+s.name+'</span><span>'+(s.duration*1000).toFixed(0)+'ms</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;margin-top:4px\"><div style=\"background:var(--accent);height:100%;width:'+width+'%;border-radius:4px\"></div></div></div>'\n})}\nshowCustomModal('🔍 追踪详情',html,'traceDetailModal')\n}).catch(function(e){alert('加载失败: '+e.message)})}\n\nfunction exportTraces(){\napi('/api/traces?limit=100').then(function(data){\nif(data.length===0){alert('暂无追踪记录');return}\nvar traceIds=data.map(function(t){return t.id});\napi('/api/traces/export',{method:'POST',body:JSON.stringify({trace_ids:traceIds,format:'jaeger'})}).then(function(result){\nvar blob=new Blob([JSON.stringify(result.data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='traces_export_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('追踪数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})\n}).catch(function(e){alert('获取追踪失败: '+e.message)})}\n\n// ========== 多 Agent 协作 ==========\nfunction loadAgents(){\napi('/api/agents').then(function(data){\nvar html=data.map(function(a){\nreturn'<label style=\"display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer\"><input type=\"checkbox\" class=\"agent-checkbox\" value=\"'+a.name+'\" checked><span>'+a.name+'</span><span style=\"font-size:11px;color:var(--text2)\">'+a.role+'</span></label>'\n}).join('');\n$('agentCheckboxes').innerHTML=html\n}).catch(function(){})}\n\nfunction runMultiAgent(){\nvar task=$('multiAgentTask').value.trim();\nif(!task){alert('请输入任务描述');return}\nvar agents=[];\ndocument.querySelectorAll('.agent-checkbox:checked').forEach(function(cb){agents.push(cb.value)});\nif(agents.length<2){alert('请至少选择2个Agent');return}\nvar mode=$('agentMode').value;\n$('multiAgentResults').style.display='block';\n$('multiAgentResultsContent').innerHTML='<p style=\"color:var(--text2)\">Agent 正在协作中...</p>';\napi('/api/agents/collaborate',{method:'POST',body:JSON.stringify({task:task,agents:agents,mode:mode})}).then(function(data){\nvar html='<div style=\"font-size:12px;color:var(--text2);margin-bottom:16px\">模式: '+data.mode+'</div>';\nfor(var name in data.results){\nhtml+='<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px;border-left:4px solid var(--accent)\"><div style=\"font-weight:500;margin-bottom:8px\">'+name+'</div><div style=\"font-size:14px;line-height:1.6\">'+marked.parse(data.results[name])+'</div></div>'\n}\n$('multiAgentResultsContent').innerHTML=html\n}).catch(function(e){$('multiAgentResultsContent').innerHTML='<p style=\"color:var(--error)\">执行失败: '+e.message+'</p>'})}\n\nfunction showCreateAgentModal(){\nvar html='<div class=\"form-group\"><label>Agent 名称</label><input type=\"text\" id=\"newAgentName\" placeholder=\"分析师\"></div><div class=\"form-group\"><label>角色描述</label><input type=\"text\" id=\"newAgentRole\" placeholder=\"数据分析专家\"></div><div class=\"form-group\"><label>使用模型</label><input type=\"text\" id=\"newAgentModel\" value=\"gpt-4o-mini\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createAgent()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'agentModal\\')\">取消</button></div>';\nshowCustomModal('创建 Agent',html,'agentModal')}\n\nfunction createAgent(){\nvar name=$('newAgentName').value.trim();\nvar role=$('newAgentRole').value.trim();\nvar model=$('newAgentModel').value.trim()||'gpt-4o-mini';\nif(!name||!role){alert('请填写名称和角色');return}\napi('/api/agents/create',{method:'POST',body:JSON.stringify({name:name,role:role,model:model})}).then(function(){\ncloseModal('agentModal');\nloadAgents();\nshowToast('Agent 已创建')\n}).catch(function(e){alert('创建失败: '+e.message)})}\n\n// ========== 系统监控 ==========\nfunction loadSystemMetrics(){\napi('/api/system/metrics').then(function(data){\n$('cpuUsage').textContent=data.cpu_percent+'%';\n$('cpuUsage').style.color=data.cpu_percent>80?'var(--error)':data.cpu_percent>50?'var(--warning)':'var(--success)';\n$('memoryUsage').textContent=data.memory_percent+'%';\n$('memoryUsage').style.color=data.memory_percent>80?'var(--error)':data.memory_percent>50?'var(--warning)':'var(--success)';\n$('diskUsage').textContent=data.disk_percent+'%';\n$('diskUsage').style.color=data.disk_percent>80?'var(--error)':data.disk_percent>50?'var(--warning)':'var(--success)';\nvar hours=Math.floor(data.uptime/3600);\nvar days=Math.floor(hours/24);\n$('uptimeDisplay').textContent=days>0?days+'d '+hours%24+'h':hours+'h';\n// 性能指标\nvar perfHtml='';\nif(data.performance){\nfor(var name in data.performance){\nvar p=data.performance[name];\nperfHtml+='<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><div style=\"font-weight:500;margin-bottom:8px\">'+name+'</div>';\nperfHtml+='<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:8px;font-size:12px\">';\nperfHtml+='<div>平均: <span style=\"color:var(--accent)\">'+p.avg_ms.toFixed(1)+'ms</span></div>';\nperfHtml+='<div>P99: <span style=\"color:var(--warning)\">'+p.p99_ms.toFixed(1)+'ms</span></div>';\nperfHtml+='<div>调用: <span style=\"color:var(--text2)\">'+p.count+'</span></div>';\nperfHtml+='</div></div>'\n}\n}\n$('performanceMetrics').innerHTML=perfHtml||'<p style=\"color:var(--text2);text-align:center\">暂无性能数据</p>'\n}).catch(function(e){console.error('加载系统指标失败:',e)})}\n\nfunction loadAlerts(){\napi('/api/system/alerts').then(function(data){\nif(data.length===0){$('alertsList').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无告警</p>';return}\nvar html=data.map(function(alert){\nvar color=alert.severity==='critical'?'var(--error)':alert.severity==='warning'?'var(--warning)':'var(--text2)';\nreturn'<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px;border-left:4px solid '+color+'\"><div style=\"display:flex;justify-content:space-between\"><span style=\"font-weight:500\">'+alert.name+'</span><span style=\"font-size:12px;color:var(--text2)\">'+alert.timestamp.slice(11,19)+'</span></div><div style=\"font-size:13px;color:var(--text2);margin-top:4px\">'+alert.message+'</div></div>'\n}).join('');\n$('alertsList').innerHTML=html\n}).catch(function(e){$('alertsList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction loadTraces(){\napi('/api/system/traces?limit=20').then(function(data){\nif(data.length===0){$('tracesList').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无追踪数据</p>';return}\nvar html=data.map(function(trace){\nvar color=trace.status==='OK'?'var(--success)':'var(--error)';\nvar duration=(trace.duration/1000).toFixed(2);\nreturn'<div style=\"padding:10px;background:var(--bg);border-radius:8px;margin-bottom:6px;font-size:13px\"><div style=\"display:flex;justify-content:space-between;align-items:center\"><span style=\"font-weight:500\">'+trace.operationName+'</span><span style=\"color:'+color+'\">'+duration+'ms</span></div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">TraceID: '+trace.traceId.slice(0,8)+'...</div></div>'\n}).join('');\n$('tracesList').innerHTML=html\n}).catch(function(e){$('tracesList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\n// ========== 任务队列 ==========\nfunction loadTaskQueue(){\napi('/api/tasks/stats').then(function(data){\n$('pendingTasks').textContent=data.by_status.pending||0;\n$('runningTasks').textContent=data.by_status.running||0;\n$('completedTasks').textContent=data.by_status.completed||0;\n$('failedTasks').textContent=data.by_status.failed||0;\nloadTasksList();\nloadScheduledJobs()\n}).catch(function(e){console.error('加载任务统计失败:',e)})}\n\nfunction loadTasksList(){\napi('/api/tasks?limit=50').then(function(data){\nif(data.length===0){$('tasksList').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无任务</p>';return}\nvar html=data.map(function(task){\nvar statusColors={pending:'var(--warning)',running:'var(--accent)',completed:'var(--success)',failed:'var(--error)',retrying:'var(--warning)'};\nvar color=statusColors[task.status]||'var(--text2)';\nreturn'<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"display:flex;justify-content:space-between;align-items:center\"><span style=\"font-weight:500\">'+task.name+'</span><span style=\"padding:2px 8px;background:'+color+';color:#fff;border-radius:4px;font-size:11px\">'+task.status+'</span></div><div style=\"font-size:12px;color:var(--text2);margin-top:6px\">ID: '+task.id.slice(0,8)+'... | 创建: '+task.created_at.slice(11,19)+(task.duration_ms?' | 耗时: '+task.duration_ms+'ms':'')+'</div>'+(task.error?'<div style=\"font-size:12px;color:var(--error);margin-top:4px\">错误: '+task.error+'</div>':'')+'</div>'\n}).join('');\n$('tasksList').innerHTML=html\n}).catch(function(e){$('tasksList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction loadScheduledJobs(){\napi('/api/tasks/scheduled').then(function(data){\nif(data.length===0){$('scheduledJobs').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无定时任务</p>';return}\nvar html=data.map(function(job){\nreturn'<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"display:flex;justify-content:space-between;align-items:center\"><span style=\"font-weight:500\">'+job.name+'</span><span style=\"font-size:12px;color:var(--text2)\">间隔: '+(job.interval/60)+'分钟</span></div><div style=\"font-size:12px;color:var(--text2);margin-top:6px\">执行次数: '+job.run_count+' | 错误: '+job.errors+(job.last_run?' | 上次: '+job.last_run.slice(11,19):'')+'</div></div>'\n}).join('');\n$('scheduledJobs').innerHTML=html\n}).catch(function(e){$('scheduledJobs').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\n// ========== 审计日志 ==========\nfunction loadAuditLogs(){\nvar event=$('auditEventFilter').value;\nvar url='/api/audit/logs?days=30';\nif(event)url+='&event='+event;\napi(url).then(function(data){\nif(data.length===0){$('auditLogsList').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无审计日志</p>';return}\nvar html=data.map(function(log){\nvar time=new Date(log.created_at).toLocaleString();\nvar details=JSON.parse(log.details||'{}');\nvar detailsStr=Object.keys(details).map(function(k){return k+': '+details[k]}).join(', ');\nreturn'<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px;border-left:4px solid var(--accent)\"><div style=\"display:flex;justify-content:space-between;margin-bottom:4px\"><span style=\"font-weight:500\">'+log.action+'</span><span style=\"font-size:12px;color:var(--text2)\">'+time+'</span></div><div style=\"font-size:13px;color:var(--text2)\">用户: '+log.user_id+' | 资源: '+log.resource+'</div>'+(detailsStr?'<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+detailsStr+'</div>':'')+'</div>'\n}).join('');\n$('auditLogsList').innerHTML=html\n}).catch(function(e){$('auditLogsList').innerHTML='<p style=\"color:var(--error);text-align:center;padding:20px\">加载失败: '+e.message+'</p>'})}\n\nfunction exportAuditLogs(){\nif(!confirm('确定导出审计日志?'))return;\napi('/api/audit/export',{method:'POST',body:JSON.stringify({days:30,format:'csv'})}).then(function(data){\nvar blob=new Blob([data.content],{type:'text/csv'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download=data.filename;\na.click();\nshowToast('审计日志已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})}\n\nfunction generateComplianceReport(period){\napi('/api/audit/report?period='+period).then(function(data){\nvar html='<div style=\"padding:20px;background:var(--bg);border-radius:12px\">';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:16px\"><strong>'+period.toUpperCase()+' 合规报告</strong><span style=\"color:var(--text2)\">'+data.generated_at.slice(0,16)+'</span></div>';\nhtml+='<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-bottom:16px\">';\nhtml+='<div style=\"text-align:center\"><div style=\"font-size:24px;font-weight:600;color:var(--accent)\">'+Object.keys(data.event_summary).length+'</div><div style=\"font-size:12px;color:var(--text2)\">事件类型</div></div>';\nhtml+='<div style=\"text-align:center\"><div style=\"font-size:24px;font-weight:600;color:'+(data.security_alerts>0?'var(--error)':'var(--success)')+'\">'+(data.security_alerts||0)+'</div><div style=\"font-size:12px;color:var(--text2)\">安全警报</div></div>';\nhtml+='<div style=\"text-align:center\"><div style=\"font-size:24px;font-weight:600;color:'+(data.compliance_status==='compliant'?'var(--success)':'var(--warning)')+'\">'+(data.compliance_status||'N/A').toUpperCase()+'</div><div style=\"font-size:12px;color:var(--text2)\">合规状态</div></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px\"><strong>事件统计:</strong><div style=\"margin-top:8px\">';\nfor(var event in data.event_summary){\nhtml+='<div style=\"display:flex;justify-content:space-between;padding:4px 0\"><span>'+event+'</span><span>'+data.event_summary[event]+'</span></div>'\n}\nhtml+='</div></div></div>';\n$('complianceReport').innerHTML=html\n}).catch(function(e){$('complianceReport').innerHTML='<p style=\"color:var(--error)\">生成失败: '+e.message+'</p>'})}\n\n// ========== 安全中心 ==========\nfunction loadSecurityStatus(){\napi('/api/security/status').then(function(data){\n$('blockedIpsCount').textContent=data.blocked_ips||0;\n$('failedAttemptsCount').textContent=data.failed_attempts_tracked||0;\n$('twoFaUsersCount').textContent=data['2fa_enabled_users']||0;\nvar score=data.blocked_ips===0&&data.failed_attempts_tracked<10?'A':'B';\n$('securityScore').textContent=score;\n$('securityScore').style.color=score==='A'?'var(--success)':'var(--warning)'\n}).catch(function(e){console.error('加载安全状态失败:',e)})}\n\nfunction unblockIP(){\nvar ip=$('unblockIpInput').value.trim();\nif(!ip){alert('请输入IP地址');return}\nif(!confirm('确定解封 '+ip+'?'))return;\napi('/api/security/unblock-ip',{method:'POST',body:JSON.stringify({ip:ip})}).then(function(){\nshowToast('IP已解封');\n$('unblockIpInput').value='';\nloadSecurityStatus()\n}).catch(function(e){alert('解封失败: '+e.message)})}\n\n// ========== 本地模型 (Ollama) ==========\nfunction loadOllamaModels(){\n$('ollamaStatus').innerHTML='<span style=\"color:var(--text2)\">检查 Ollama 连接...</span>';\napi('/api/ollama/models').then(function(data){\nif(data.error){\n$('ollamaStatus').innerHTML='<span style=\"color:var(--error)\">❌ '+data.error+'</span>';\n$('ollamaModelList').innerHTML='';\n$('ollamaModelSelect').innerHTML='<option>无可用模型</option>';\nreturn}\n$('ollamaStatus').innerHTML='<span style=\"color:var(--success)\">✅ Ollama 已连接,共 '+data.models.length+' 个模型</span>';\nvar html=data.models.map(function(m){\nvar size=(m.size/1024/1024/1024).toFixed(1);\nreturn'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div><strong>'+m.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+size+' GB</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"selectOllamaModel(\\''+m.name+'\\')\">使用</button></div>'\n}).join('');\n$('ollamaModelList').innerHTML=html||'<p style=\"color:var(--text2)\">暂无模型,请先拉取</p>';\nvar selectHtml=data.models.map(function(m){return'<option value=\"'+m.name+'\">'+m.name+'</option>'}).join('');\n$('ollamaModelSelect').innerHTML=selectHtml||'<option>无可用模型</option>'\n}).catch(function(e){$('ollamaStatus').innerHTML='<span style=\"color:var(--error)\">❌ 连接失败</span>'})}\n\nfunction showPullModelModal(){\nvar html='<div class=\"form-group\"><label>模型名称</label><input type=\"text\" id=\"pullModelName\" placeholder=\"llama2, mistral, codellama...\"></div><p style=\"font-size:12px;color:var(--text2);margin-bottom:16px\">常用模型: llama2, mistral, codellama, phi, gemma</p><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"pullOllamaModel()\">拉取</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pullModal\\')\">取消</button></div>';\nshowCustomModal('拉取 Ollama 模型',html,'pullModal')}\n\nfunction pullOllamaModel(){\nvar model=$('pullModelName').value.trim();\nif(!model){alert('请输入模型名称');return}\nshowToast('开始拉取 '+model+',请稍候...');\ncloseModal('pullModal');\napi('/api/ollama/pull',{method:'POST',body:JSON.stringify({model:model})}).then(function(data){\nif(data.success){showToast('模型拉取成功!');loadOllamaModels()}else{alert('拉取失败')}\n}).catch(function(e){alert('拉取失败: '+e.message)})}\n\nfunction selectOllamaModel(name){$('ollamaModelSelect').value=name;showToast('已选择 '+name)}\n\nfunction chatWithOllama(){\nvar model=$('ollamaModelSelect').value;\nvar message=$('ollamaMessage').value.trim();\nif(!model||!message){alert('请选择模型并输入消息');return}\n$('ollamaResponse').style.display='block';\n$('ollamaResponse').innerHTML='<p style=\"color:var(--text2)\">思考中...</p>';\napi('/api/ollama/chat',{method:'POST',body:JSON.stringify({model:model,messages:[{role:'user',content:message}]})}).then(function(data){\nvar content=data.message?data.message.content:'无响应';\n$('ollamaResponse').innerHTML=marked.parse(content)\n}).catch(function(e){$('ollamaResponse').innerHTML='<p style=\"color:var(--error)\">错误: '+e.message+'</p>'})}\n\nfunction loadVLLMModels(){\nvar url=$('vllmUrl').value.trim();\n$('vllmStatus').innerHTML='<span style=\"color:var(--text2)\">检查连接...</span>';\nfetch(url+'/v1/models').then(function(r){return r.json()}).then(function(data){\nif(data.data&&data.data.length>0){\n$('vllmStatus').innerHTML='<span style=\"color:var(--success)\">✅ vLLM 已连接,模型: '+data.data.map(function(m){return m.id}).join(', ')+'</span>'\n}else{\n$('vllmStatus').innerHTML='<span style=\"color:var(--warning)\">⚠️ 已连接但无模型</span>'\n}\n}).catch(function(){$('vllmStatus').innerHTML='<span style=\"color:var(--error)\">❌ 无法连接到 vLLM</span>'})}\n\n// ========== RAG 检索 ==========\nfunction loadRAGKnowledgeBases(){\napi('/api/knowledge-bases').then(function(data){\nvar html='<option value=\"\">选择知识库</option>';\ndata.forEach(function(kb){html+='<option value=\"'+kb.id+'\">'+kb.name+'</option>'});\n$('ragKbSelect').innerHTML=html\n}).catch(function(){})}\n\nfunction searchRAG(){\nvar kbId=$('ragKbSelect').value;\nvar query=$('ragQuery').value.trim();\nif(!kbId){alert('请选择知识库');return}\nif(!query){alert('请输入问题');return}\n$('ragResults').innerHTML='<p style=\"color:var(--text2)\">搜索中...</p>';\napi('/api/rag/search',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),query:query,top_k:5})}).then(function(data){\nif(data.results.length===0){$('ragResults').innerHTML='<p style=\"color:var(--text2)\">未找到相关内容</p>';return}\nvar html=data.results.map(function(r,i){\nreturn'<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px;border-left:4px solid var(--accent)\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span style=\"font-weight:500\">#'+(i+1)+' '+r.chunk_id+'</span><span style=\"color:var(--accent)\">相似度: '+(r.score*100).toFixed(1)+'%</span></div><div style=\"font-size:14px;color:var(--text2);line-height:1.6\">'+r.content.slice(0,300)+(r.content.length>300?'...':'')+'</div></div>'\n}).join('');\n$('ragResults').innerHTML=html\n}).catch(function(e){$('ragResults').innerHTML='<p style=\"color:var(--error)\">搜索失败: '+e.message+'</p>'})}\n\nfunction chatWithRAG(){\nvar kbId=$('ragKbSelect').value;\nvar query=$('ragQuery').value.trim();\nif(!kbId){alert('请选择知识库');return}\nif(!query){alert('请输入问题');return}\n$('ragResults').innerHTML='<p style=\"color:var(--text2)\">AI 正在思考...</p>';\napi('/api/rag/chat',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),question:query})}).then(function(data){\nvar html='<div style=\"padding:20px;background:var(--bg);border-radius:12px\"><div style=\"font-size:14px;line-height:1.8\">'+marked.parse(data.answer)+'</div>';\nif(data.sources&&data.sources.length>0){\nhtml+='<div style=\"margin-top:16px;padding-top:16px;border-top:1px solid var(--border)\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:8px\">参考来源:</div>';\ndata.sources.forEach(function(s){html+='<span class=\"tag\" style=\"margin-right:8px\">'+s.chunk_id+' ('+(s.score*100).toFixed(0)+'%)</span>'});\nhtml+='</div>'}\nhtml+='</div>';\n$('ragResults').innerHTML=html\n}).catch(function(e){$('ragResults').innerHTML='<p style=\"color:var(--error)\">对话失败: '+e.message+'</p>'})}\n\nfunction indexDocument(){\nvar kbId=$('ragKbSelect').value;\nvar content=$('ragContent').value.trim();\nvar filename=$('ragFilename').value.trim()||'document.txt';\nif(!kbId){alert('请选择知识库');return}\nif(!content){alert('请输入文档内容');return}\nshowToast('正在索引文档...');\napi('/api/rag/index',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),content:content,filename:filename})}).then(function(data){\nshowToast('索引完成,共 '+data.indexed_chunks+' 个分块');\n$('ragContent').value='';\n$('ragFilename').value=''\n}).catch(function(e){alert('索引失败: '+e.message)})}\n\n// ========== 计费系统 ==========\nfunction loadBillingPlans(){\napi('/api/billing/plans').then(function(data){\nvar html=data.map(function(p){\nvar features=JSON.parse(p.features||'[]');\nreturn'<div class=\"price-card\" onclick=\"subscribePlan(\\''+p.id+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">¥'+p.price+'<span>/月</span></div><ul>'+features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn btn-primary\" style=\"width:100%\">选择</button></div>'\n}).join('');\n$('billingPlans').innerHTML=html\n}).catch(function(){})}\n\nfunction loadSubscription(){\napi('/api/billing/subscription').then(function(data){\n$('currentPlanName').textContent=data.plan_name||data.plan||'免费版';\nvar remaining=data.tokens_limit===-1?'无限':formatNumber(data.tokens_limit||10000);\n$('remainingQuota').textContent=remaining\n}).catch(function(){})}\n\nfunction loadUsageStats(){\napi('/api/billing/usage?period=month').then(function(data){\nvar html='';\nfor(var type in data.usage){\nvar u=data.usage[type];\nhtml+='<div style=\"padding:16px;background:var(--bg);border-radius:10px;text-align:center\"><div style=\"font-size:24px;font-weight:600;color:var(--accent)\">'+formatNumber(u.amount)+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+type+'</div><div style=\"font-size:11px;color:var(--success);margin-top:4px\">¥'+u.cost.toFixed(2)+'</div></div>'\n}\n$('usageStats').innerHTML=html||'<p style=\"color:var(--text2);grid-column:1/-1;text-align:center\">暂无用量数据</p>'\n}).catch(function(){})}\n\nfunction loadInvoices(){\napi('/api/billing/invoices').then(function(data){\nif(data.length===0){$('invoiceList').innerHTML='<p style=\"color:var(--text2)\">暂无发票</p>';return}\nvar html=data.map(function(inv){\nvar statusColor=inv.status==='paid'?'var(--success)':'var(--warning)';\nreturn'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div><div style=\"font-weight:500\">'+inv.id+'</div><div style=\"font-size:12px;color:var(--text2)\">'+(inv.created_at||'').slice(0,10)+'</div></div><div style=\"text-align:right\"><div style=\"font-weight:600\">¥'+inv.amount+'</div><div style=\"font-size:12px;color:'+statusColor+'\">'+(inv.status==='paid'?'已支付':'待支付')+'</div></div>'+(inv.status!=='paid'?'<button class=\"btn btn-primary btn-sm\" onclick=\"payInvoice(\\''+inv.id+'\\')\">支付</button>':'')+'</div>'\n}).join('');\n$('invoiceList').innerHTML=html\n}).catch(function(){})}\n\nfunction subscribePlan(planId){\nif(!authToken){alert('请先登录');return}\nif(!confirm('确定订阅此套餐?'))return;\napi('/api/billing/subscribe',{method:'POST',body:JSON.stringify({plan_id:planId,months:1})}).then(function(data){\nshowToast('订阅成功,请支付发票');\nloadInvoices();\nloadSubscription()\n}).catch(function(e){alert('订阅失败: '+e.message)})}\n\nfunction payInvoice(invoiceId){\nif(!confirm('确定支付?'))return;\napi('/api/billing/pay/'+invoiceId,{method:'POST',body:JSON.stringify({method:'alipay'})}).then(function(){\nshowToast('支付成功!');\nloadInvoices();\nloadSubscription()\n}).catch(function(e){alert('支付失败: '+e.message)})}\n\n// ========== RBAC 权限 ==========\nfunction loadMyPermissions(){\napi('/api/rbac/my-permissions').then(function(data){\nvar html=data.permissions.map(function(p){\nreturn'<span class=\"tag tag-primary\">'+p+'</span>'\n}).join('');\n$('myPermissions').innerHTML=html||'<span style=\"color:var(--text2)\">暂无权限</span>'\n}).catch(function(){})}\n\nfunction loadRoles(){\napi('/api/rbac/roles').then(function(data){\nvar html=data.map(function(r){\nvar perms=JSON.parse(r.permissions||'[]');\nreturn'<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong>'+r.name+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.description+'</span></div><div style=\"display:flex;flex-wrap:wrap;gap:6px\">'+perms.map(function(p){return'<span class=\"tag\">'+p+'</span>'}).join('')+'</div></div>'\n}).join('');\n$('rolesList').innerHTML=html\n}).catch(function(){})}\n\nfunction showCreateRoleModal(){\nvar html='<div class=\"form-group\"><label>角色名称</label><input type=\"text\" id=\"newRoleName\" placeholder=\"role_name\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"newRoleDesc\" placeholder=\"角色描述\"></div><div class=\"form-group\"><label>权限(逗号分隔)</label><input type=\"text\" id=\"newRolePerms\" placeholder=\"chat,notes,memory\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createRole()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'roleModal\\')\">取消</button></div>';\nshowCustomModal('创建角色',html,'roleModal')}\n\nfunction createRole(){\nvar name=$('newRoleName').value.trim();\nvar desc=$('newRoleDesc').value.trim();\nvar perms=$('newRolePerms').value.split(',').map(function(p){return p.trim()}).filter(function(p){return p});\nif(!name){alert('请输入角色名称');return}\napi('/api/rbac/roles',{method:'POST',body:JSON.stringify({name:name,description:desc,permissions:perms})}).then(function(){\ncloseModal('roleModal');\nloadRoles();\nshowToast('角色已创建')\n}).catch(function(e){alert('创建失败: '+e.message)})}\n\n// 初始化时加载推荐\nsetTimeout(loadRecommendations,1000);\nsetTimeout(loadIntegrations,100);\n\n// ========== 快捷键帮助 ==========\nfunction showHotkeyHelp(){\nvar html='<div style=\"display:grid;gap:8px\">';\nvar hotkeys=[\n['Ctrl + N','新建对话'],\n['Ctrl + K','全局搜索'],\n['Ctrl + D','切换主题'],\n['Ctrl + H','系统状态'],\n['Ctrl + B','批量选择'],\n['Ctrl + F','搜索当前对话'],\n['Ctrl + /','快捷键帮助'],\n['Enter','发送消息'],\n['Shift + Enter','换行'],\n['Escape','关闭弹窗']\n];\nhotkeys.forEach(function(h){\nhtml+='<div class=\"hotkey-help-item\"><span>'+h[1]+'</span><span class=\"hotkey-help-key\">'+h[0]+'</span></div>'\n});\nhtml+='</div>';\nshowCustomModal('⌨️ 快捷键帮助',html,'hotkeyHelpModal')}\n\n// ========== 欢迎引导 ==========\nfunction showWelcomeGuide(){\nif(localStorage.getItem('welcomeShown'))return;\nvar html='<div style=\"text-align:center;padding:20px\"><div style=\"font-size:48px;margin-bottom:16px\">🤖</div><h2 style=\"margin-bottom:12px\">欢迎使用 AI Hub</h2><p style=\"color:var(--text2);margin-bottom:24px\">一站式 AI 平台,支持多模型、多功能</p><div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:12px;text-align:left;margin-bottom:24px\"><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">💬</span><div style=\"font-weight:500;margin-top:8px\">多模型对话</div><div style=\"font-size:12px;color:var(--text2)\">支持 OpenAI、Claude、Gemini 等</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">🎨</span><div style=\"font-weight:500;margin-top:8px\">图片生成</div><div style=\"font-size:12px;color:var(--text2)\">DALL-E 3 AI 绘图</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">📚</span><div style=\"font-weight:500;margin-top:8px\">知识库</div><div style=\"font-size:12px;color:var(--text2)\">上传文档,智能问答</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">👥</span><div style=\"font-weight:500;margin-top:8px\">团队协作</div><div style=\"font-size:12px;color:var(--text2)\">多人共享对话和资源</div></div></div><button class=\"btn btn-primary\" onclick=\"closeModal(\\'welcomeModal\\');localStorage.setItem(\\'welcomeShown\\',\\'1\\')\">开始使用</button></div>';\nshowCustomModal('',html,'welcomeModal')}\nsetTimeout(showWelcomeGuide,500);\n\n// 初始化主题\n(function(){\nvar savedTheme=localStorage.getItem('theme')||'dark';\ndocument.documentElement.setAttribute('data-theme',savedTheme);\n})();\n\nconsole.log('🚀 AI Hub v2.0.0 - Enhanced');\n</script>\n</body>\n</html>\n"}, "3fe55f7deee2178023766905e0b335aba53a9de9": {"t": 1785765453.3987956, "n": 261062, "h": "00a3c6eac77eca8a", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"theme-color\" content=\"#0f0f1a\">\n<meta name=\"description\" content=\"AI Hub - 统一 AI 平台\">\n<link rel=\"manifest\" href=\"/static/manifest.json\">\n<link rel=\"apple-touch-icon\" href=\"/static/icon-192.png\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0;overflow-y:auto;overflow-x:hidden}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px;flex:1;overflow-y:auto}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"local-models\"><span class=\"nav-item-icon\">🏠</span> 本地模型</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"traces\"><span class=\"nav-item-icon\">🔍</span> 链路追踪</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n<div class=\"nav-item\" data-page=\"rag\"><span class=\"nav-item-icon\">🔍</span> RAG 检索</div>\n<div class=\"nav-item\" data-page=\"billing\"><span class=\"nav-item-icon\">💳</span> 订阅计费</div>\n<div class=\"nav-item\" data-page=\"rbac\"><span class=\"nav-item-icon\">🛡️</span> 权限管理</div>\n<div class=\"nav-item\" data-page=\"audit\"><span class=\"nav-item-icon\">📜</span> 审计日志</div>\n<div class=\"nav-item\" data-page=\"security\"><span class=\"nav-item-icon\">🔒</span> 安全中心</div>\n<div class=\"nav-item\" data-page=\"monitoring\"><span class=\"nav-item-icon\">📊</span> 系统监控</div>\n<div class=\"nav-item\" data-page=\"tasks\"><span class=\"nav-item-icon\">⚙️</span> 任务队列</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"integrations\"><span class=\"nav-item-icon\">🔗</span> 第三方集成</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"workflows\"><span class=\"nav-item-icon\">🤖</span> Agent 工作流</div>\n<div class=\"nav-item\" data-page=\"code-runner\"><span class=\"nav-item-icon\">▶️</span> 代码运行</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" onclick=\"showHealthDashboard()\"><span class=\"nav-item-icon\">🖥️</span> 系统状态</div>\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\" title=\"批量操作\">☑️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div id=\"batchActions\" style=\"display:none;padding:8px;background:var(--bg3);gap:8px;align-items:center\">\n<span style=\"font-size:12px\">已选 <span id=\"selectedCount\">0</span> 个</span>\n<button class=\"btn btn-danger btn-sm\" onclick=\"batchDeleteChats()\">删除</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"batchExportChats()\">导出</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\">取消</button>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"quickReplies\" style=\"display:none;padding:8px 0;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap\"></div>\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateImage()\" title=\"生成图片\">🎨</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateMindmap()\" title=\"生成思维导图\">🧠</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"saveAsTemplate()\" title=\"保存为模板\">💾</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 本地模型页 -->\n<div id=\"page-local-models\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🏠</span> 本地模型 (Ollama)</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">使用 Ollama 运行本地大语言模型,数据完全私有</p>\n<div style=\"display:flex;gap:12px;margin-bottom:20px\">\n<button class=\"btn btn-primary\" onclick=\"loadOllamaModels()\">🔄 刷新模型</button>\n<button class=\"btn btn-ghost\" onclick=\"showPullModelModal()\">📥 拉取模型</button>\n<a href=\"https://ollama.ai\" target=\"_blank\" class=\"btn btn-ghost\">📖 Ollama 官网</a>\n</div>\n<div id=\"ollamaStatus\" style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:16px\"></div>\n<div id=\"ollamaModelList\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 本地模型对话</h4>\n<div class=\"form-group\"><label>选择模型</label><select id=\"ollamaModelSelect\" style=\"width:100%;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select></div>\n<div class=\"form-group\"><label>消息</label><textarea id=\"ollamaMessage\" rows=\"4\" placeholder=\"输入消息...\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"chatWithOllama()\">发送</button>\n<div id=\"ollamaResponse\" style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:8px;min-height:100px;display:none\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚡</span> vLLM 服务</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">高性能推理服务器</p>\n<div class=\"form-group\"><label>vLLM 地址</label><input type=\"text\" id=\"vllmUrl\" value=\"http://localhost:8080\" placeholder=\"http://localhost:8080\"></div>\n<button class=\"btn btn-ghost\" onclick=\"loadVLLMModels()\">检查连接</button>\n<div id=\"vllmStatus\" style=\"margin-top:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">双因素认证 (2FA)<br><small style=\"color:var(--text2)\">使用 Google Authenticator 等应用增强账户安全</small></div><div style=\"display:flex;gap:8px\"><span id=\"2faStatus\" style=\"color:var(--text2)\">未启用</span><button class=\"btn btn-ghost btn-sm\" onclick=\"setup2FA()\" id=\"2faBtn\">设置</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录设备管理</div><button class=\"btn btn-ghost btn-sm\" onclick=\"alert('功能开发中')\">查看设备</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">修改密码</div><button class=\"btn btn-ghost btn-sm\" onclick=\"showChangePasswordModal()\">修改</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复<br><small style=\"color:var(--text2)\">导出/导入所有数据(对话、笔记、记忆、设置)</small></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-primary\" onclick=\"exportAllData()\">📤 导出全部</button><button class=\"btn btn-ghost\" onclick=\"importAllData()\">📥 导入数据</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据库优化<br><small style=\"color:var(--text2)\">清理过期数据,优化数据库性能</small></div><button class=\"btn btn-ghost\" onclick=\"optimizeDatabase()\">🔧 优化数据库</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n<button class=\"btn btn-primary\" onclick=\"showUsageAnalytics()\">📈 详细分析</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 链路追踪页 -->\n<div id=\"page-traces\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔍</span> 链路追踪</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"loadTraces()\">🔄 刷新</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportTraces()\">📥 导出</button>\n</div>\n</div>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:20px\">监控 API 请求的完整调用链路,分析性能瓶颈</p>\n<div id=\"tracesList\"><p style=\"color:var(--text2)\">点击刷新加载追踪记录</p></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 性能概览</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--accent)\" id=\"traceAvgLatency\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">平均延迟</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--success)\" id=\"traceSuccessRate\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">成功率</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--warning)\" id=\"traceCount\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总追踪数</div>\n</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- RAG 检索页 -->\n<div id=\"page-rag\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> RAG 语义检索</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">基于向量的语义搜索,让 AI 理解你的文档内容</p>\n<div class=\"form-group\"><label>选择知识库</label><select id=\"ragKbSelect\" style=\"width:100%;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select></div>\n<div class=\"form-group\"><label>搜索问题</label><input type=\"text\" id=\"ragQuery\" placeholder=\"输入你的问题...\"></div>\n<button class=\"btn btn-primary\" onclick=\"searchRAG()\">🔍 语义搜索</button>\n<button class=\"btn btn-ghost\" onclick=\"chatWithRAG()\" style=\"margin-left:8px\">💬 RAG 对话</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 搜索结果</h4>\n<div id=\"ragResults\" style=\"min-height:100px\"><p style=\"color:var(--text2)\">输入问题后点击搜索</p></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📤</span> 索引文档</h4>\n<div class=\"form-group\"><label>文档内容</label><textarea id=\"ragContent\" rows=\"6\" placeholder=\"粘贴文档内容...\"></textarea></div>\n<div class=\"form-group\"><label>文件名</label><input type=\"text\" id=\"ragFilename\" placeholder=\"document.txt\"></div>\n<button class=\"btn btn-primary\" onclick=\"indexDocument()\">📥 索引文档</button>\n</div>\n</div></div></div></div>\n<!-- 订阅计费页 -->\n<div id=\"page-billing\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💳</span> 订阅计费</h4>\n<div id=\"currentSubscription\" style=\"padding:20px;background:var(--bg);border-radius:12px;margin-bottom:20px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div><div style=\"font-size:12px;color:var(--text2)\">当前套餐</div><div style=\"font-size:24px;font-weight:600\" id=\"currentPlanName\">免费版</div></div>\n<div style=\"text-align:right\"><div style=\"font-size:12px;color:var(--text2)\">剩余额度</div><div style=\"font-size:24px;font-weight:600;color:var(--accent)\" id=\"remainingQuota\">10,000</div></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 套餐选择</h4>\n<div id=\"billingPlans\" class=\"price-cards\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 用量统计</h4>\n<div id=\"usageStats\" style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🧾</span> 发票记录</h4>\n<div id=\"invoiceList\"></div>\n</div>\n</div></div></div></div>\n<!-- 权限管理页 -->\n<div id=\"page-rbac\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🛡️</span> 权限管理</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">基于角色的访问控制 (RBAC)</p>\n<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<div style=\"font-size:12px;color:var(--text2);margin-bottom:8px\">我的权限</div>\n<div id=\"myPermissions\" style=\"display:flex;flex-wrap:wrap;gap:8px\"></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👥</span> 角色列表</h4>\n<div id=\"rolesList\"></div>\n<button class=\"btn btn-ghost\" onclick=\"showCreateRoleModal()\" style=\"margin-top:12px\">+ 创建角色</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> 权限说明</h4>\n<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:12px;font-size:13px\">\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>chat</strong> - 对话功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>notes</strong> - 笔记功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>memory</strong> - 全局记忆</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>image</strong> - 图片生成</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>code</strong> - 代码运行</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>rag</strong> - RAG 检索</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>admin</strong> - 管理功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>*</strong> - 所有权限</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 审计日志页 -->\n<div id=\"page-audit\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📜</span> 审计日志</h4>\n<div style=\"display:flex;gap:8px\">\n<select id=\"auditEventFilter\" style=\"padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\" onchange=\"loadAuditLogs()\">\n<option value=\"\">全部事件</option>\n<option value=\"user.login\">用户登录</option>\n<option value=\"data.export\">数据导出</option>\n<option value=\"settings.change\">设置变更</option>\n<option value=\"payment.create\">支付创建</option>\n<option value=\"security.alert\">安全警报</option>\n</select>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"loadAuditLogs()\">🔄 刷新</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportAuditLogs()\">📥 导出</button>\n</div>\n</div>\n<div id=\"auditLogsList\" style=\"max-height:400px;overflow-y:auto\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 合规报告</h4>\n<div style=\"display:flex;gap:12px;margin-bottom:16px\">\n<button class=\"btn btn-primary\" onclick=\"generateComplianceReport('month')\">月度报告</button>\n<button class=\"btn btn-ghost\" onclick=\"generateComplianceReport('quarter')\">季度报告</button>\n<button class=\"btn btn-ghost\" onclick=\"generateComplianceReport('year')\">年度报告</button>\n</div>\n<div id=\"complianceReport\"></div>\n</div>\n</div></div></div></div>\n<!-- 安全中心页 -->\n<div id=\"page-security\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔒</span> 安全中心</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:20px\">\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"blockedIpsCount\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">封禁 IP</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"failedAttemptsCount\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">失败尝试</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"twoFaUsersCount\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">2FA 用户</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"securityScore\">A</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">安全评分</div>\n</div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"loadSecurityStatus()\">🔄 刷新状态</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> IP 封禁管理</h4>\n<div class=\"form-group\"><label>解封 IP</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"unblockIpInput\" placeholder=\"192.168.1.1\"><button class=\"btn btn-ghost\" onclick=\"unblockIP()\">解封</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">强制密码复杂度<br><small style=\"color:var(--text2)\">要求密码包含大小写、数字和特殊字符</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录失败锁定<br><small style=\"color:var(--text2)\">5次失败后锁定1小时</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">会话超时<br><small style=\"color:var(--text2)\">30天无活动自动登出</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 系统监控页 -->\n<div id=\"page-monitoring\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 系统监控</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:20px\">\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"cpuUsage\">0%</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">CPU 使用率</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"memoryUsage\">0%</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">内存使用率</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"diskUsage\">0%</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">磁盘使用率</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--text)\" id=\"uptimeDisplay\">0h</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">运行时间</div>\n</div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"loadSystemMetrics()\">🔄 刷新指标</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 性能指标</h4>\n<div id=\"performanceMetrics\" style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 告警列表</h4>\n<div id=\"alertsList\" style=\"max-height:300px;overflow-y:auto\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> 链路追踪</h4>\n<div id=\"tracesList\" style=\"max-height:300px;overflow-y:auto\"></div>\n</div>\n</div></div></div></div>\n<!-- 任务队列页 -->\n<div id=\"page-tasks\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 任务队列</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:20px\">\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"pendingTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">待处理</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"runningTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">运行中</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"completedTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">已完成</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"failedTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">失败</div>\n</div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"loadTaskQueue()\">🔄 刷新队列</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 任务列表</h4>\n<div id=\"tasksList\" style=\"max-height:400px;overflow-y:auto\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⏰</span> 定时任务</h4>\n<div id=\"scheduledJobs\" style=\"max-height:300px;overflow-y:auto\"></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- 第三方集成页 -->\n<div id=\"page-integrations\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔗</span> 第三方集成</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:20px\">连接 Slack、飞书等平台,让 AI 助手无处不在</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> Slack 集成</h4>\n<div class=\"form-group\"><label>Bot Token</label><input type=\"password\" id=\"slackToken\" placeholder=\"xoxb-...\" onchange=\"saveIntegration('slack')\"></div>\n<div class=\"form-group\"><label>Signing Secret</label><input type=\"password\" id=\"slackSecret\" placeholder=\"签名密钥\" onchange=\"saveIntegration('slack')\"></div>\n<div class=\"form-group\"><label>Webhook URL</label><div style=\"display:flex;gap:8px\"><input type=\"text\" value=\"http://localhost:8000/api/integrations/slack/webhook\" readonly style=\"flex:1;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText(this.previousElementSibling.value)\">📋</button></div></div>\n<div style=\"display:flex;gap:12px;margin-top:16px\">\n<button class=\"btn btn-primary\" onclick=\"testSlackIntegration()\">🧪 测试连接</button>\n<button class=\"btn btn-ghost\" onclick=\"window.open('https://api.slack.com/apps','_blank')\">📖 创建 Slack App</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐦</span> 飞书集成</h4>\n<div class=\"form-group\"><label>App ID</label><input type=\"text\" id=\"feishuAppId\" placeholder=\"cli_...\" onchange=\"saveIntegration('feishu')\"></div>\n<div class=\"form-group\"><label>App Secret</label><input type=\"password\" id=\"feishuSecret\" placeholder=\"应用密钥\" onchange=\"saveIntegration('feishu')\"></div>\n<div class=\"form-group\"><label>Webhook URL</label><div style=\"display:flex;gap:8px\"><input type=\"text\" value=\"http://localhost:8000/api/integrations/feishu/webhook\" readonly style=\"flex:1;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText(this.previousElementSibling.value)\">📋</button></div></div>\n<div style=\"display:flex;gap:12px;margin-top:16px\">\n<button class=\"btn btn-primary\" onclick=\"testFeishuIntegration()\">🧪 测试连接</button>\n<button class=\"btn btn-ghost\" onclick=\"window.open('https://open.feishu.cn/app','_blank')\">📖 创建飞书应用</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> Webhook 通知</h4>\n<div class=\"form-group\"><label>通知 URL</label><input type=\"text\" id=\"webhookUrl\" placeholder=\"https://your-server.com/webhook\" onchange=\"saveIntegration('webhook')\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">新消息通知</div><label class=\"switch\"><input type=\"checkbox\" id=\"webhookNewMsg\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">错误通知</div><label class=\"switch\"><input type=\"checkbox\" id=\"webhookError\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🎛️</span> 灰度发布</h4>\n<div id=\"featureFlagsList\"></div>\n<button class=\"btn btn-ghost\" onclick=\"loadFeatureFlags()\" style=\"margin-top:12px\">🔄 刷新</button>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Agent 工作流页 -->\n<div id=\"page-workflows\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🤖</span> Agent 工作流</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建多步骤自动化任务,让 AI 按流程完成复杂工作</p>\n<div id=\"workflowTemplates\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👥</span> 多 Agent 协作</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">多个 AI Agent 协同完成复杂任务</p>\n<div class=\"form-group\"><label>任务描述</label><textarea id=\"multiAgentTask\" rows=\"3\" placeholder=\"描述你需要完成的任务...\"></textarea></div>\n<div class=\"form-group\"><label>选择 Agent</label>\n<div id=\"agentCheckboxes\" style=\"display:flex;flex-wrap:wrap;gap:12px\"></div>\n</div>\n<div class=\"form-group\"><label>协作模式</label>\n<select id=\"agentMode\" style=\"width:200px;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\">\n<option value=\"sequential\">顺序执行</option>\n<option value=\"parallel\">并行执行</option>\n<option value=\"debate\">辩论模式</option>\n</select>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runMultiAgent()\">🚀 开始协作</button>\n<button class=\"btn btn-ghost\" onclick=\"showCreateAgentModal()\" style=\"margin-left:8px\">+ 创建 Agent</button>\n</div>\n<div class=\"settings-section\" id=\"multiAgentResults\" style=\"display:none\">\n<h4><span>📋</span> 协作结果</h4>\n<div id=\"multiAgentResultsContent\"></div>\n</div>\n<div class=\"settings-section\" id=\"workflowRunner\" style=\"display:none\">\n<h4><span>▶️</span> 运行工作流</h4>\n<div id=\"workflowInputs\"></div>\n<button class=\"btn btn-primary\" onclick=\"executeWorkflow()\">🚀 执行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('workflowRunner').style.display='none'\">取消</button>\n</div>\n<div class=\"settings-section\" id=\"workflowResults\" style=\"display:none\">\n<h4><span>📋</span> 执行结果</h4>\n<div id=\"workflowResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 代码运行器页 -->\n<div id=\"page-code-runner\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>▶️</span> 代码运行器</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">在线运行 Python / JavaScript 代码</p>\n<div class=\"form-group\">\n<label>语言</label>\n<select id=\"codeLanguage\" style=\"width:150px\">\n<option value=\"python\">Python</option>\n<option value=\"javascript\">JavaScript</option>\n</select>\n</div>\n<div class=\"form-group\">\n<label>代码</label>\n<textarea id=\"codeInput\" rows=\"12\" style=\"font-family:monospace;font-size:13px\" placeholder=\"# 输入代码...\nprint('Hello, World!')\"></textarea>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-primary\" onclick=\"runCode()\">▶️ 运行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('codeInput').value=''\">清空</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 输出结果</h4>\n<pre id=\"codeOutput\" style=\"background:var(--bg);padding:16px;border-radius:8px;min-height:100px;font-family:monospace;font-size:13px;white-space:pre-wrap\">等待运行...</pre>\n</div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>系统状态</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + H</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量选择模式</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + B</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量导出</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>搜索当前对话</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + F</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换主题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + D</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><div class=\"form-group\" id=\"auth2FAGroup\" style=\"display:none\"><label>2FA 验证码</label><input type=\"text\" id=\"auth2FACode\" placeholder=\"6位验证码\" maxlength=\"6\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><div style=\"display:flex;align-items:center;margin:16px 0\"><div style=\"flex:1;height:1px;background:var(--border)\"></div><span style=\"padding:0 12px;color:var(--text2);font-size:12px\">或</span><div style=\"flex:1;height:1px;background:var(--border)\"></div></div><button class=\"btn btn-ghost\" style=\"width:100%;display:flex;align-items:center;justify-content:center;gap:8px\" onclick=\"loginWithGithub()\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg> 使用 GitHub 登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();if(n.dataset.page==='workflows')loadWorkflowTemplates();if(n.dataset.page==='traces')loadTraces();if(n.dataset.page==='integrations')loadFeatureFlags();if(n.dataset.page==='rag')loadRAGKnowledgeBases();if(n.dataset.page==='billing'){loadBillingPlans();loadSubscription();loadUsageStats();loadInvoices()}if(n.dataset.page==='rbac'){loadMyPermissions();loadRoles()}if(n.dataset.page==='local-models')loadOllamaModels();if(n.dataset.page==='workflows')loadAgents();if(n.dataset.page==='audit')loadAuditLogs();if(n.dataset.page==='security')loadSecurityStatus();if(n.dataset.page==='monitoring'){loadSystemMetrics();loadAlerts();loadTraces()}if(n.dataset.page==='tasks')loadTaskQueue();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{\n// 先显示置顶的对话\nvar pinnedChats=chats.filter(function(c){return c.pinned});\nvar normalChats=chats.filter(function(c){return !c.pinned&&!c.archived});\nif(pinnedChats.length>0){html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2)\">📌 置顶</div>';pinnedChats.forEach(function(c){html+=renderChatItem(c)})}\nif(normalChats.length>0){if(pinnedChats.length>0)html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2);margin-top:8px\">💬 对话</div>';normalChats.forEach(function(c){html+=renderChatItem(c)})}}$('chatList').innerHTML=html}\nfunction renderChatItem(c){var selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';var checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';var pinIcon=c.pinned?'📌':'💬';return'<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" style=\"'+selected+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">'+pinIcon+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"favoriteMessageByIndex('+i+')\" title=\"收藏\">❤️</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll();showQuickReplies()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var chat=chats.find(function(c){return c.id===id});var pinText=chat&&chat.pinned?'📌 取消置顶':'📌 置顶';var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"togglePinChat(\\''+id+'\\')\">'+pinText+'</div><div onclick=\"archiveChat(\\''+id+'\\')\">📦 归档</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction togglePinChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.pinned=!chat.pinned;saveChats();renderChats();showToast(chat.pinned?'已置顶':'已取消置顶');if(authToken){api('/api/conversations/'+id+'/pin',{method:'POST'}).catch(function(){})}}\nfunction archiveChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.archived=true;chats=chats.filter(function(c){return c.id!==id});saveChats();renderChats();showToast('已归档');if(authToken){api('/api/conversations/'+id+'/archive',{method:'POST'}).catch(function(){})}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Agent 工作流\nvar workflowTemplates=[];\nvar currentWorkflow=null;\nfunction loadWorkflowTemplates(){api('/api/workflows/templates').then(function(data){workflowTemplates=data;renderWorkflowTemplates()}).catch(function(e){console.error('加载工作流失败:',e)})}\nfunction renderWorkflowTemplates(){var html=workflowTemplates.map(function(w){return'<div style=\"background:var(--bg);border-radius:12px;padding:20px;cursor:pointer\" onclick=\"selectWorkflow(\\''+w.id+'\\')\"><div style=\"display:flex;align-items:center;gap:12px;margin-bottom:12px\"><span style=\"font-size:24px\">🤖</span><div><strong>'+w.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+w.steps.length+' 个步骤</div></div></div><p style=\"font-size:13px;color:var(--text2);line-height:1.5\">'+w.description+'</p></div>'}).join('');$('workflowTemplates').innerHTML=html||'<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无工作流模板</div>'}\nfunction selectWorkflow(id){currentWorkflow=workflowTemplates.find(function(w){return w.id===id});if(!currentWorkflow)return;var inputs=[];currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')&&inputs.indexOf(key)===-1)inputs.push(key)})}});var html=inputs.map(function(key){return'<div class=\"form-group\"><label>'+key+'</label><textarea id=\"wf_'+key+'\" rows=\"3\" placeholder=\"输入 '+key+'\"></textarea></div>'}).join('');$('workflowInputs').innerHTML='<h5 style=\"margin-bottom:16px\">'+currentWorkflow.name+'</h5>'+html;$('workflowRunner').style.display='block';$('workflowResults').style.display='none'}\nfunction executeWorkflow(){if(!currentWorkflow){alert('请先选择工作流');return}var inputData={};currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')){var el=$('wf_'+key);if(el)inputData[key]=el.value}})}});$('workflowResultsContent').innerHTML='<div style=\"text-align:center;padding:40px\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px;color:var(--text2)\">正在执行工作流...</p></div>';$('workflowResults').style.display='block';api('/api/workflows/run',{method:'POST',body:JSON.stringify({name:currentWorkflow.name,steps:currentWorkflow.steps,input_data:inputData})}).then(function(data){var html='';for(var key in data.results){html+='<div style=\"background:var(--bg);border-radius:10px;padding:16px;margin-bottom:12px\"><div style=\"font-weight:600;margin-bottom:8px;color:var(--accent)\">'+key+'</div><div style=\"font-size:14px;line-height:1.6;white-space:pre-wrap\">'+data.results[key]+'</div></div>'}$('workflowResultsContent').innerHTML=html}).catch(function(e){$('workflowResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">执行失败: '+e.message+'</div>'})}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// GitHub 登录\nfunction loginWithGithub(){window.location.href='/api/auth/github'}\n// 2FA 设置\nfunction setup2FA(){if(!authToken){alert('请先登录');return}api('/api/auth/2fa/setup',{method:'POST'}).then(function(data){var html='<div style=\"text-align:center\"><img src=\"'+data.qr_code+'\" style=\"width:200px;height:200px;border-radius:8px\"><p style=\"margin:16px 0;color:var(--text2);font-size:13px\">使用 Google Authenticator 扫描二维码</p><div class=\"form-group\"><label>输入6位验证码确认</label><input type=\"text\" id=\"verify2FACode\" placeholder=\"000000\" maxlength=\"6\" style=\"text-align:center;font-size:20px;letter-spacing:8px\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"verify2FA()\">确认启用</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'2faModal\\')\">取消</button></div></div>';showCustomModal('设置双因素认证',html,'2faModal')}).catch(function(e){alert('设置失败: '+e.message)})}\nfunction verify2FA(){var code=$('verify2FACode').value.trim();if(code.length!==6){alert('请输入6位验证码');return}api('/api/auth/2fa/verify',{method:'POST',body:JSON.stringify({code:code})}).then(function(data){closeModal('2faModal');$('2faStatus').textContent='已启用';$('2faStatus').style.color='var(--success)';$('2faBtn').textContent='禁用';$('2faBtn').onclick=disable2FA;showToast('2FA 已启用')}).catch(function(e){alert('验证失败: '+e.message)})}\nfunction disable2FA(){var code=prompt('输入6位验证码以禁用 2FA:');if(!code)return;api('/api/auth/2fa/disable',{method:'POST',body:JSON.stringify({code:code})}).then(function(){$('2faStatus').textContent='未启用';$('2faStatus').style.color='var(--text2)';$('2faBtn').textContent='设置';$('2faBtn').onclick=setup2FA;showToast('2FA 已禁用')}).catch(function(e){alert('禁用失败: '+e.message)})}\nfunction showChangePasswordModal(){var html='<div class=\"form-group\"><label>当前密码</label><input type=\"password\" id=\"oldPassword\"></div><div class=\"form-group\"><label>新密码</label><input type=\"password\" id=\"newPassword\"></div><div class=\"form-group\"><label>确认新密码</label><input type=\"password\" id=\"confirmPassword\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"changePassword()\">修改</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pwdModal\\')\">取消</button></div>';showCustomModal('修改密码',html,'pwdModal')}\nfunction changePassword(){var oldPwd=$('oldPassword').value,newPwd=$('newPassword').value,confirmPwd=$('confirmPassword').value;if(!oldPwd||!newPwd){alert('请填写密码');return}if(newPwd!==confirmPwd){alert('两次密码不一致');return}alert('密码修改功能开发中')}\n// 检查 URL 中的 token(OAuth 回调)\n(function(){var params=new URLSearchParams(window.location.search);var token=params.get('token');if(token){localStorage.setItem('token',token);authToken=token;window.history.replaceState({},document.title,'/');checkAuth()}})();\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\n// 代码运行器\nfunction runCode(){var code=$('codeInput').value;var lang=$('codeLanguage').value;if(!code.trim()){alert('请输入代码');return}$('codeOutput').textContent='运行中...';$('codeOutput').style.color='var(--text2)';api('/api/code/run',{method:'POST',body:JSON.stringify({code:code,language:lang,timeout:5})}).then(function(data){if(data.success){$('codeOutput').textContent=data.output||'(无输出)';$('codeOutput').style.color='var(--success)'}else{$('codeOutput').textContent='错误: '+(data.error||'未知错误')+'\\n'+data.output;$('codeOutput').style.color='var(--error)'}}).catch(function(e){$('codeOutput').textContent='请求失败: '+e.message;$('codeOutput').style.color='var(--error)'})}\n// 思维导图\nfunction generateMindmap(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}showToast('正在生成思维导图...');api('/api/mindmap/generate',{method:'POST',body:JSON.stringify({messages:chat.messages,title:chat.title})}).then(function(data){renderMindmap(data.nodes)}).catch(function(e){alert('生成失败: '+e.message)})}\nfunction renderMindmap(nodes){var html='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.8);z-index:2000;display:flex;align-items:center;justify-content:center\" onclick=\"if(event.target===this)this.remove()\"><div style=\"background:var(--bg2);border-radius:16px;padding:24px;max-width:800px;max-height:80vh;overflow:auto\"><h3 style=\"margin-bottom:16px\">🧠 思维导图</h3><div id=\"mindmapContent\" style=\"padding:20px\"></div><button class=\"btn btn-ghost\" onclick=\"this.parentElement.parentElement.remove()\">关闭</button></div></div>';document.body.insertAdjacentHTML('beforeend',html);var content='';function renderNode(node,level){var indent=level*24;content+='<div style=\"margin-left:'+indent+'px;padding:8px 12px;margin-bottom:4px;background:var(--bg'+(level>0?'3':'')+');border-radius:6px;border-left:3px solid var(--accent)\">'+(level>0?'├─ ':'')+node.label+'</div>';if(node.children){node.children.forEach(function(c){renderNode(c,level+1)})}}if(nodes&&nodes.length)renderNode(nodes[0],0);$('mindmapContent').innerHTML=content||'<p style=\"color:var(--text2)\">无法生成思维导图</p>'}\n// 保存对话为模板\nfunction saveAsTemplate(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}var name=prompt('模板名称:',chat.title);if(!name)return;api('/api/chat-templates',{method:'POST',body:JSON.stringify({name:name,messages:chat.messages})}).then(function(){showToast('已保存为模板')}).catch(function(e){alert('保存失败: '+e.message)})}\n// 用量配额\nfunction loadQuota(){api('/api/quota').then(function(data){var html='<div style=\"margin-bottom:16px\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Token 使用量</span><span>'+formatNumber(data.tokens_used)+' / '+formatNumber(data.tokens_limit)+'</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;overflow:hidden\"><div style=\"background:var(--accent);height:100%;width:'+data.usage_percent+'%\"></div></div></div><p style=\"font-size:12px;color:var(--text2)\">当前套餐: '+data.plan+'</p>';if($('quotaInfo'))$('quotaInfo').innerHTML=html}).catch(function(e){console.error(e)})}\n// PWA 注册\nif('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js').then(function(reg){console.log('SW registered');if('Notification' in window&&Notification.permission==='default'){Notification.requestPermission()}}).catch(function(e){console.error('SW failed:',e)})}\n// 图片生成\nfunction generateImage(){var prompt=prompt('输入图片描述:');if(!prompt)return;showToast('正在生成图片...');api('/api/images/generate',{method:'POST',body:JSON.stringify({prompt:prompt})}).then(function(data){var img='<img src=\"'+data.url+'\" style=\"max-width:100%;border-radius:8px\">';var chat=chats.find(function(c){return c.id===currentChatId});if(chat){chat.messages.push({role:'assistant',content:'![生成的图片]('+data.url+')\\n\\n'+data.revised_prompt});saveChats();renderMessages()}showToast('图片已生成')}).catch(function(e){alert('生成失败: '+e.message)})}\n// TTS 语音合成\nfunction speakText(text){api('/api/audio/tts',{method:'POST',body:JSON.stringify({text:text,voice:'alloy'})}).then(function(data){var audio=new Audio(data.audio);audio.play();showToast('正在播放')}).catch(function(e){if('speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(text);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('TTS 失败: '+e.message)}})}\n// 内容过滤\nfunction filterContent(text){return api('/api/content/filter',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data})}\n// 数据脱敏\nfunction maskData(text){return api('/api/data/mask',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data.masked})}\n// 备份\nfunction createBackup(){api('/api/backup',{method:'POST'}).then(function(data){showToast('备份已创建: '+data.path)}).catch(function(e){alert('备份失败: '+e.message)})}\n// 离线检测\nwindow.addEventListener('online',function(){showToast('网络已恢复')});\nwindow.addEventListener('offline',function(){showToast('网络已断开,部分功能不可用')});\n\n// ========== 性能监控面板 ==========\nfunction showHealthDashboard(){\napi('/api/health/detailed').then(function(data){\nvar html='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">CPU 使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.cpu_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.cpu_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">内存使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.memory_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.memory_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">磁盘使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.disk_percent>90?'var(--error)':'var(--success)')+'\">'+data.system.disk_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">数据库延迟</div><div style=\"font-size:24px;font-weight:600;color:'+(data.components.database.latency_ms>100?'var(--warning)':'var(--success)')+'\">'+data.components.database.latency_ms+'ms</div></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:10px\">';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>缓存</span><span>'+data.components.cache.size+'/'+data.components.cache.max_size+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Redis</span><span style=\"color:'+(data.components.redis.status==='healthy'?'var(--success)':'var(--warning)')+'\">'+data.components.redis.status+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between\"><span>待处理任务</span><span>'+data.components.task_queue.pending_tasks+'</span></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;text-align:center;font-size:12px;color:var(--text2)\">版本 '+data.version+' · 运行时间 '+formatUptime(data.uptime_seconds)+'</div>';\nshowCustomModal('🖥️ 系统状态',html,'healthModal')\n}).catch(function(e){alert('获取状态失败: '+e.message)})}\nfunction formatUptime(seconds){var h=Math.floor(seconds/3600);var m=Math.floor((seconds%3600)/60);return h+'小时'+m+'分钟'}\n\n// ========== 批量操作 ==========\nvar batchMode=false;\nvar selectedChats=[];\nfunction toggleBatchMode(){batchMode=!batchMode;selectedChats=[];if(batchMode){$('batchActions').style.display='flex';showToast('已进入批量选择模式')}else{$('batchActions').style.display='none'}renderChatList()}\nfunction toggleChatSelection(id,e){if(!batchMode)return;e.stopPropagation();var idx=selectedChats.indexOf(id);if(idx>=0){selectedChats.splice(idx,1)}else{selectedChats.push(id)}renderChatList();$('selectedCount').textContent=selectedChats.length}\nfunction batchDeleteChats(){if(selectedChats.length===0){alert('请先选择对话');return}if(!confirm('确定删除 '+selectedChats.length+' 个对话?'))return;api('/api/conversations/batch-delete',{method:'POST',body:JSON.stringify({ids:selectedChats})}).then(function(data){showToast('已删除 '+data.deleted+' 个对话');selectedChats=[];batchMode=false;$('batchActions').style.display='none';loadChats()}).catch(function(e){alert('删除失败: '+e.message)})}\nfunction batchExportChats(){if(selectedChats.length===0){alert('请先选择对话');return}api('/api/messages/batch-export',{method:'POST',body:JSON.stringify({conversation_ids:selectedChats,format:'json'})}).then(function(data){var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='conversations_export.json';a.click();showToast('已导出 '+data.count+' 个对话')}).catch(function(e){alert('导出失败: '+e.message)})}\n\n// ========== 数据库优化 ==========\nfunction optimizeDatabase(){if(!confirm('确定要优化数据库?这将清理过期数据。'))return;showToast('正在优化...');api('/api/admin/optimize-db',{method:'POST'}).then(function(data){showToast(data.message)}).catch(function(e){alert('优化失败: '+e.message)})}\n\n// ========== 快捷键增强 ==========\ndocument.addEventListener('keydown',function(e){\nif(e.ctrlKey&&e.key==='h'){e.preventDefault();showHealthDashboard()}\nif(e.ctrlKey&&e.key==='b'){e.preventDefault();toggleBatchMode()}\nif(e.ctrlKey&&e.shiftKey&&e.key==='E'){e.preventDefault();batchExportChats()}\nif(e.ctrlKey&&e.key==='f'){e.preventDefault();searchInCurrentChat()}\nif(e.ctrlKey&&e.key==='/'||e.key==='?'){e.preventDefault();showHotkeyHelp()}\n});\n\n// ========== 性能优化:虚拟滚动 ==========\nfunction renderChatListVirtual(){\nvar container=$('chatList');\nvar itemHeight=60;\nvar visibleCount=Math.ceil(container.clientHeight/itemHeight)+2;\nvar scrollTop=container.scrollTop;\nvar startIndex=Math.floor(scrollTop/itemHeight);\nvar endIndex=Math.min(startIndex+visibleCount,chats.length);\nvar html='<div style=\"height:'+(startIndex*itemHeight)+'px\"></div>';\nfor(var i=startIndex;i<endIndex;i++){\nvar c=chats[i];\nvar active=c.id===currentChatId?'active':'';\nvar selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';\nvar checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';\nhtml+='<div class=\"sidebar-item '+active+'\" style=\"'+selected+'\" onclick=\"loadChat(\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+c.title+'</div><div class=\"sidebar-item-desc\">'+(c.messages.length||0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" style=\"opacity:0\" onclick=\"deleteChat(\\''+c.id+'\\',event)\">🗑️</button></div>'\n}\nhtml+='<div style=\"height:'+((chats.length-endIndex)*itemHeight)+'px\"></div>';\ncontainer.innerHTML=html}\n\n// ========== 请求重试机制 ==========\nasync function apiWithRetry(url,options,maxRetries=3){\nfor(var i=0;i<maxRetries;i++){\ntry{return await api(url,options)}\ncatch(e){\nif(i===maxRetries-1)throw e;\nawait new Promise(function(r){setTimeout(r,1000*(i+1))});\nconsole.log('Retrying request...',i+1)\n}}}\n\n// ========== 消息队列(离线支持) ==========\nvar offlineQueue=JSON.parse(localStorage.getItem('offlineQueue')||'[]');\nfunction queueOfflineMessage(msg){offlineQueue.push({msg:msg,time:Date.now()});localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))}\nfunction processOfflineQueue(){if(offlineQueue.length===0)return;showToast('正在发送离线消息...');var msg=offlineQueue.shift();localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue));sendMessageInternal(msg.msg).then(function(){processOfflineQueue()}).catch(function(){offlineQueue.unshift(msg);localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))})}\nwindow.addEventListener('online',processOfflineQueue);\n\n// ========== 智能预加载 ==========\nfunction preloadNextChat(){\nvar currentIdx=chats.findIndex(function(c){return c.id===currentChatId});\nif(currentIdx>=0&&currentIdx<chats.length-1){\nvar nextChat=chats[currentIdx+1];\nif(!nextChat.messages||nextChat.messages.length===0){\napi('/api/conversations/'+nextChat.id+'/messages').then(function(msgs){nextChat.messages=msgs})}}}\n\n// ========== 自动保存草稿 ==========\nvar draftTimer=null;\nfunction saveDraft(){var input=$('chatInput').value;if(input&&currentChatId){localStorage.setItem('draft_'+currentChatId,input)}}\nfunction loadDraft(){if(currentChatId){var draft=localStorage.getItem('draft_'+currentChatId);if(draft)$('chatInput').value=draft}}\nfunction clearDraft(){if(currentChatId)localStorage.removeItem('draft_'+currentChatId)}\n$('chatInput').addEventListener('input',function(){clearTimeout(draftTimer);draftTimer=setTimeout(saveDraft,1000)});\n\n// ========== 消息搜索增强 ==========\nfunction searchInCurrentChat(){var q=prompt('在当前对话中搜索:');if(!q)return;var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages)return;var results=chat.messages.filter(function(m){return m.content&&m.content.toLowerCase().includes(q.toLowerCase())});if(results.length===0){alert('未找到匹配消息');return}var html='<div style=\"max-height:400px;overflow-y:auto\">';results.forEach(function(m,i){html+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:4px\">'+(m.role==='user'?'👤 用户':'🤖 助手')+'</div><div style=\"font-size:14px\">'+m.content.slice(0,200)+(m.content.length>200?'...':'')+'</div></div>'});html+='</div>';showCustomModal('搜索结果 ('+results.length+')',html,'searchResultModal')}\n\n// ========== 快速回复 ==========\nvar quickReplies=[\n{id:'continue',text:'继续',prompt:'请继续'},\n{id:'explain',text:'解释',prompt:'请详细解释一下'},\n{id:'example',text:'举例',prompt:'请举个例子'},\n{id:'simplify',text:'简化',prompt:'请用更简单的语言解释'},\n{id:'code',text:'代码',prompt:'请给出代码示例'},\n{id:'summary',text:'总结',prompt:'请总结一下要点'}\n];\nfunction showQuickReplies(){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages||chat.messages.length===0){$('quickReplies').style.display='none';return}\nvar lastMsg=chat.messages[chat.messages.length-1];\nif(lastMsg.role!=='assistant'){$('quickReplies').style.display='none';return}\nvar html=quickReplies.map(function(r){return'<button class=\"btn btn-ghost btn-sm\" onclick=\"sendQuickReply(\\''+r.prompt+'\\')\">'+r.text+'</button>'}).join('');\n$('quickReplies').innerHTML=html;\n$('quickReplies').style.display='flex'}\nfunction sendQuickReply(prompt){$('chatInput').value=prompt;sendMessage()}\n\n// ========== 数据导入导出 ==========\nfunction exportAllData(){\nif(!authToken){alert('请先登录');return}\nshowToast('正在导出数据...');\napi('/api/data/export-all',{method:'POST'}).then(function(data){\nvar blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='ai_hub_backup_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})}\n\nfunction importAllData(){\nif(!authToken){alert('请先登录');return}\nvar input=document.createElement('input');\ninput.type='file';\ninput.accept='.json';\ninput.onchange=function(e){\nvar file=e.target.files[0];\nif(!file)return;\nvar reader=new FileReader();\nreader.onload=function(ev){\ntry{\nvar data=JSON.parse(ev.target.result);\nif(!confirm('确定要导入数据?这将添加 '+\n(data.conversations?data.conversations.length:0)+' 个对话、'+\n(data.notes?data.notes.length:0)+' 个笔记'))return;\napi('/api/data/import',{method:'POST',body:JSON.stringify(data)}).then(function(result){\nshowToast('导入完成: '+result.imported.conversations+' 对话, '+result.imported.notes+' 笔记');\nloadChats()\n}).catch(function(e){alert('导入失败: '+e.message)})\n}catch(e){alert('文件格式错误')}};\nreader.readAsText(file)};\ninput.click()}\n\n// ========== 智能推荐 ==========\nfunction loadRecommendations(){\napi('/api/recommendations').then(function(data){\nif(data.features&&data.features.length>0){\nvar html='<div style=\"padding:16px;background:var(--bg3);border-radius:10px;margin-bottom:16px\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:12px\">💡 推荐功能</div><div style=\"display:flex;gap:12px;flex-wrap:wrap\">';\ndata.features.forEach(function(f){\nhtml+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;cursor:pointer;flex:1;min-width:150px\" onclick=\"showFeatureGuide(\\''+f.name+'\\')\"><span style=\"font-size:20px\">'+f.icon+'</span><div style=\"font-size:14px;font-weight:500;margin-top:8px\">'+f.name+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+f.desc+'</div></div>'});\nhtml+='</div></div>';\nvar container=$('chatMessages');\nif(container&&container.querySelector('.empty-state')){\ncontainer.innerHTML=html+container.innerHTML}}\n}).catch(function(){})}\nfunction showFeatureGuide(name){\nvar guides={\n'知识库':'点击左侧导航的\"知识库\",创建知识库并上传文档,AI 将基于您的资料回答问题。',\n'团队协作':'点击左侧导航的\"团队空间\",创建团队并邀请成员,共享对话和资源。'\n};\nalert(guides[name]||'功能介绍开发中')}\n\n// ========== 收藏消息 ==========\nfunction favoriteMessage(content){\nif(!authToken){alert('请先登录');return}\napi('/api/messages/favorite',{method:'POST',body:JSON.stringify({\nconversation_id:currentChatId,\ncontent:content\n})}).then(function(){showToast('已收藏到记忆')}).catch(function(e){alert('收藏失败: '+e.message)})}\nfunction favoriteMessageByIndex(index){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages[index])return;\nfavoriteMessage(chat.messages[index].content)}\n\n// ========== 使用分析 ==========\nfunction showUsageAnalytics(){\napi('/api/analytics/usage?days=30').then(function(data){\nvar html='<div style=\"margin-bottom:20px\"><h4 style=\"margin-bottom:12px\">📊 30天使用趋势</h4>';\nif(data.daily_usage.length>0){\nvar maxCalls=Math.max.apply(null,data.daily_usage.map(function(d){return d.calls}));\nhtml+='<div style=\"display:flex;align-items:flex-end;gap:4px;height:100px\">';\ndata.daily_usage.forEach(function(d){\nvar height=Math.max(5,(d.calls/maxCalls)*100);\nhtml+='<div style=\"flex:1;background:var(--accent);border-radius:2px 2px 0 0;height:'+height+'px\" title=\"'+d.day+': '+d.calls+'次\"></div>'});\nhtml+='</div>'}\nhtml+='</div>';\nhtml+='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">总调用次数</div><div style=\"font-size:24px;font-weight:600\">'+data.total_calls+'</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">错误率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.error_rate>5?'var(--error)':'var(--success)')+'\">'+data.error_rate+'%</div></div>';\nhtml+='</div>';\nshowCustomModal('📈 使用分析',html,'analyticsModal')\n}).catch(function(e){alert('获取分析失败: '+e.message)})}\n\n// ========== 第三方集成 ==========\nfunction saveIntegration(type){\nvar data={};\nif(type==='slack'){\ndata={slack_token:$('slackToken').value,slack_secret:$('slackSecret').value}\n}else if(type==='feishu'){\ndata={feishu_app_id:$('feishuAppId').value,feishu_secret:$('feishuSecret').value}\n}else if(type==='webhook'){\ndata={webhook_url:$('webhookUrl').value,webhook_new_msg:$('webhookNewMsg').checked,webhook_error:$('webhookError').checked}\n}\nlocalStorage.setItem('integration_'+type,JSON.stringify(data));\nshowToast('配置已保存')}\n\nfunction loadIntegrations(){\ntry{\nvar slack=JSON.parse(localStorage.getItem('integration_slack')||'{}');\nif(slack.slack_token)$('slackToken').value=slack.slack_token;\nif(slack.slack_secret)$('slackSecret').value=slack.slack_secret;\nvar feishu=JSON.parse(localStorage.getItem('integration_feishu')||'{}');\nif(feishu.feishu_app_id)$('feishuAppId').value=feishu.feishu_app_id;\nif(feishu.feishu_secret)$('feishuSecret').value=feishu.feishu_secret;\nvar webhook=JSON.parse(localStorage.getItem('integration_webhook')||'{}');\nif(webhook.webhook_url)$('webhookUrl').value=webhook.webhook_url;\nif(webhook.webhook_new_msg)$('webhookNewMsg').checked=true;\nif(webhook.webhook_error)$('webhookError').checked=true;\n}catch(e){}}\n\nfunction testSlackIntegration(){\nshowToast('测试 Slack 连接...');\napi('/api/integrations/slack/send',{method:'POST',body:JSON.stringify({channel:'#general',text:'AI Hub 测试消息'})}).then(function(data){\nif(data.ok){showToast('Slack 连接成功!')}else{alert('连接失败: '+(data.error||'未知错误'))}\n}).catch(function(e){alert('连接失败: '+e.message)})}\n\nfunction testFeishuIntegration(){\nshowToast('测试飞书连接...');\napi('/api/integrations/feishu/send',{method:'POST',body:JSON.stringify({chat_id:'test',text:'AI Hub 测试消息'})}).then(function(data){\nif(data.code===0){showToast('飞书连接成功!')}else{alert('连接失败: '+(data.msg||'未知错误'))}\n}).catch(function(e){alert('连接失败: '+e.message)})}\n\n// ========== 灰度发布 ==========\nfunction loadFeatureFlags(){\napi('/api/features/all').then(function(data){\nvar html='';\nfor(var name in data){\nvar flag=data[name];\nhtml+='<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\">';\nhtml+='<div><strong>'+name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">灰度比例: '+flag.percentage+'% · 白名单用户: '+(flag.users?flag.users.length:0)+'</div></div>';\nhtml+='<label class=\"switch\"><input type=\"checkbox\" '+(flag.enabled?'checked':'')+' onchange=\"toggleFeatureFlag(\\''+name+'\\',this.checked)\"><span class=\"switch-slider\"></span></label>';\nhtml+='</div>'}\n$('featureFlagsList').innerHTML=html||'<p style=\"color:var(--text2)\">暂无功能开关</p>'\n}).catch(function(e){$('featureFlagsList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction toggleFeatureFlag(name,enabled){\napi('/api/features/'+name,{method:'POST',body:JSON.stringify({enabled:enabled})}).then(function(){\nshowToast(name+(enabled?' 已启用':' 已禁用'))\n}).catch(function(e){alert('操作失败: '+e.message)})}\n\nfunction updateFeatureFlagPercentage(name,percentage){\napi('/api/features/'+name,{method:'POST',body:JSON.stringify({percentage:parseInt(percentage)})}).then(function(){\nshowToast('灰度比例已更新')\n}).catch(function(e){alert('操作失败: '+e.message)})}\n\n// ========== 链路追踪 ==========\nfunction loadTraces(){\napi('/api/traces?limit=50').then(function(data){\nif(data.length===0){$('tracesList').innerHTML='<p style=\"color:var(--text2)\">暂无追踪记录</p>';return}\nvar html='<table style=\"width:100%;border-collapse:collapse;font-size:13px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">ID</th><th style=\"padding:10px\">名称</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">Spans</th></tr>';\ndata.forEach(function(t){\nhtml+='<tr style=\"border-top:1px solid var(--border);cursor:pointer\" onclick=\"showTraceDetail(\\''+t.id+'\\')\">';\nhtml+='<td style=\"padding:10px;font-family:monospace\">'+t.id+'</td>';\nhtml+='<td style=\"padding:10px\">'+t.name+'</td>';\nhtml+='<td style=\"padding:10px;text-align:right\">'+(t.total_duration?(t.total_duration*1000).toFixed(0)+'ms':'-')+'</td>';\nhtml+='<td style=\"padding:10px\">'+(t.spans?t.spans.length:0)+'</td>';\nhtml+='</tr>'});\nhtml+='</table>';\n$('tracesList').innerHTML=html\n}).catch(function(e){$('tracesList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction showTraceDetail(traceId){\napi('/api/traces/'+traceId).then(function(data){\nvar html='<div style=\"margin-bottom:16px\"><strong>Trace ID:</strong> '+data.id+'<br><strong>名称:</strong> '+data.name+'<br><strong>总耗时:</strong> '+(data.total_duration?(data.total_duration*1000).toFixed(0)+'ms':'-')+'</div>';\nif(data.spans&&data.spans.length>0){\nhtml+='<h4 style=\"margin-bottom:12px\">Spans</h4>';\ndata.spans.forEach(function(s,i){\nvar width=Math.min(100,s.duration*100);\nhtml+='<div style=\"margin-bottom:8px\"><div style=\"display:flex;justify-content:space-between;font-size:13px\"><span>'+s.name+'</span><span>'+(s.duration*1000).toFixed(0)+'ms</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;margin-top:4px\"><div style=\"background:var(--accent);height:100%;width:'+width+'%;border-radius:4px\"></div></div></div>'\n})}\nshowCustomModal('🔍 追踪详情',html,'traceDetailModal')\n}).catch(function(e){alert('加载失败: '+e.message)})}\n\nfunction exportTraces(){\napi('/api/traces?limit=100').then(function(data){\nif(data.length===0){alert('暂无追踪记录');return}\nvar traceIds=data.map(function(t){return t.id});\napi('/api/traces/export',{method:'POST',body:JSON.stringify({trace_ids:traceIds,format:'jaeger'})}).then(function(result){\nvar blob=new Blob([JSON.stringify(result.data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='traces_export_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('追踪数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})\n}).catch(function(e){alert('获取追踪失败: '+e.message)})}\n\n// ========== 多 Agent 协作 ==========\nfunction loadAgents(){\napi('/api/agents').then(function(data){\nvar html=data.map(function(a){\nreturn'<label style=\"display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer\"><input type=\"checkbox\" class=\"agent-checkbox\" value=\"'+a.name+'\" checked><span>'+a.name+'</span><span style=\"font-size:11px;color:var(--text2)\">'+a.role+'</span></label>'\n}).join('');\n$('agentCheckboxes').innerHTML=html\n}).catch(function(){})}\n\nfunction runMultiAgent(){\nvar task=$('multiAgentTask').value.trim();\nif(!task){alert('请输入任务描述');return}\nvar agents=[];\ndocument.querySelectorAll('.agent-checkbox:checked').forEach(function(cb){agents.push(cb.value)});\nif(agents.length<2){alert('请至少选择2个Agent');return}\nvar mode=$('agentMode').value;\n$('multiAgentResults').style.display='block';\n$('multiAgentResultsContent').innerHTML='<p style=\"color:var(--text2)\">Agent 正在协作中...</p>';\napi('/api/agents/collaborate',{method:'POST',body:JSON.stringify({task:task,agents:agents,mode:mode})}).then(function(data){\nvar html='<div style=\"font-size:12px;color:var(--text2);margin-bottom:16px\">模式: '+data.mode+'</div>';\nfor(var name in data.results){\nhtml+='<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px;border-left:4px solid var(--accent)\"><div style=\"font-weight:500;margin-bottom:8px\">'+name+'</div><div style=\"font-size:14px;line-height:1.6\">'+marked.parse(data.results[name])+'</div></div>'\n}\n$('multiAgentResultsContent').innerHTML=html\n}).catch(function(e){$('multiAgentResultsContent').innerHTML='<p style=\"color:var(--error)\">执行失败: '+e.message+'</p>'})}\n\nfunction showCreateAgentModal(){\nvar html='<div class=\"form-group\"><label>Agent 名称</label><input type=\"text\" id=\"newAgentName\" placeholder=\"分析师\"></div><div class=\"form-group\"><label>角色描述</label><input type=\"text\" id=\"newAgentRole\" placeholder=\"数据分析专家\"></div><div class=\"form-group\"><label>使用模型</label><input type=\"text\" id=\"newAgentModel\" value=\"gpt-4o-mini\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createAgent()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'agentModal\\')\">取消</button></div>';\nshowCustomModal('创建 Agent',html,'agentModal')}\n\nfunction createAgent(){\nvar name=$('newAgentName').value.trim();\nvar role=$('newAgentRole').value.trim();\nvar model=$('newAgentModel').value.trim()||'gpt-4o-mini';\nif(!name||!role){alert('请填写名称和角色');return}\napi('/api/agents/create',{method:'POST',body:JSON.stringify({name:name,role:role,model:model})}).then(function(){\ncloseModal('agentModal');\nloadAgents();\nshowToast('Agent 已创建')\n}).catch(function(e){alert('创建失败: '+e.message)})}\n\n// ========== 系统监控 ==========\nfunction loadSystemMetrics(){\napi('/api/system/metrics').then(function(data){\n$('cpuUsage').textContent=data.cpu_percent+'%';\n$('cpuUsage').style.color=data.cpu_percent>80?'var(--error)':data.cpu_percent>50?'var(--warning)':'var(--success)';\n$('memoryUsage').textContent=data.memory_percent+'%';\n$('memoryUsage').style.color=data.memory_percent>80?'var(--error)':data.memory_percent>50?'var(--warning)':'var(--success)';\n$('diskUsage').textContent=data.disk_percent+'%';\n$('diskUsage').style.color=data.disk_percent>80?'var(--error)':data.disk_percent>50?'var(--warning)':'var(--success)';\nvar hours=Math.floor(data.uptime/3600);\nvar days=Math.floor(hours/24);\n$('uptimeDisplay').textContent=days>0?days+'d '+hours%24+'h':hours+'h';\n// 性能指标\nvar perfHtml='';\nif(data.performance){\nfor(var name in data.performance){\nvar p=data.performance[name];\nperfHtml+='<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><div style=\"font-weight:500;margin-bottom:8px\">'+name+'</div>';\nperfHtml+='<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:8px;font-size:12px\">';\nperfHtml+='<div>平均: <span style=\"color:var(--accent)\">'+p.avg_ms.toFixed(1)+'ms</span></div>';\nperfHtml+='<div>P99: <span style=\"color:var(--warning)\">'+p.p99_ms.toFixed(1)+'ms</span></div>';\nperfHtml+='<div>调用: <span style=\"color:var(--text2)\">'+p.count+'</span></div>';\nperfHtml+='</div></div>'\n}\n}\n$('performanceMetrics').innerHTML=perfHtml||'<p style=\"color:var(--text2);text-align:center\">暂无性能数据</p>'\n}).catch(function(e){console.error('加载系统指标失败:',e)})}\n\nfunction loadAlerts(){\napi('/api/system/alerts').then(function(data){\nif(data.length===0){$('alertsList').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无告警</p>';return}\nvar html=data.map(function(alert){\nvar color=alert.severity==='critical'?'var(--error)':alert.severity==='warning'?'var(--warning)':'var(--text2)';\nreturn'<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px;border-left:4px solid '+color+'\"><div style=\"display:flex;justify-content:space-between\"><span style=\"font-weight:500\">'+alert.name+'</span><span style=\"font-size:12px;color:var(--text2)\">'+alert.timestamp.slice(11,19)+'</span></div><div style=\"font-size:13px;color:var(--text2);margin-top:4px\">'+alert.message+'</div></div>'\n}).join('');\n$('alertsList').innerHTML=html\n}).catch(function(e){$('alertsList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction loadTraces(){\napi('/api/system/traces?limit=20').then(function(data){\nif(data.length===0){$('tracesList').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无追踪数据</p>';return}\nvar html=data.map(function(trace){\nvar color=trace.status==='OK'?'var(--success)':'var(--error)';\nvar duration=(trace.duration/1000).toFixed(2);\nreturn'<div style=\"padding:10px;background:var(--bg);border-radius:8px;margin-bottom:6px;font-size:13px\"><div style=\"display:flex;justify-content:space-between;align-items:center\"><span style=\"font-weight:500\">'+trace.operationName+'</span><span style=\"color:'+color+'\">'+duration+'ms</span></div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">TraceID: '+trace.traceId.slice(0,8)+'...</div></div>'\n}).join('');\n$('tracesList').innerHTML=html\n}).catch(function(e){$('tracesList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\n// ========== 任务队列 ==========\nfunction loadTaskQueue(){\napi('/api/tasks/stats').then(function(data){\n$('pendingTasks').textContent=data.by_status.pending||0;\n$('runningTasks').textContent=data.by_status.running||0;\n$('completedTasks').textContent=data.by_status.completed||0;\n$('failedTasks').textContent=data.by_status.failed||0;\nloadTasksList();\nloadScheduledJobs()\n}).catch(function(e){console.error('加载任务统计失败:',e)})}\n\nfunction loadTasksList(){\napi('/api/tasks?limit=50').then(function(data){\nif(data.length===0){$('tasksList').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无任务</p>';return}\nvar html=data.map(function(task){\nvar statusColors={pending:'var(--warning)',running:'var(--accent)',completed:'var(--success)',failed:'var(--error)',retrying:'var(--warning)'};\nvar color=statusColors[task.status]||'var(--text2)';\nreturn'<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"display:flex;justify-content:space-between;align-items:center\"><span style=\"font-weight:500\">'+task.name+'</span><span style=\"padding:2px 8px;background:'+color+';color:#fff;border-radius:4px;font-size:11px\">'+task.status+'</span></div><div style=\"font-size:12px;color:var(--text2);margin-top:6px\">ID: '+task.id.slice(0,8)+'... | 创建: '+task.created_at.slice(11,19)+(task.duration_ms?' | 耗时: '+task.duration_ms+'ms':'')+'</div>'+(task.error?'<div style=\"font-size:12px;color:var(--error);margin-top:4px\">错误: '+task.error+'</div>':'')+'</div>'\n}).join('');\n$('tasksList').innerHTML=html\n}).catch(function(e){$('tasksList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction loadScheduledJobs(){\napi('/api/tasks/scheduled').then(function(data){\nif(data.length===0){$('scheduledJobs').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无定时任务</p>';return}\nvar html=data.map(function(job){\nreturn'<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"display:flex;justify-content:space-between;align-items:center\"><span style=\"font-weight:500\">'+job.name+'</span><span style=\"font-size:12px;color:var(--text2)\">间隔: '+(job.interval/60)+'分钟</span></div><div style=\"font-size:12px;color:var(--text2);margin-top:6px\">执行次数: '+job.run_count+' | 错误: '+job.errors+(job.last_run?' | 上次: '+job.last_run.slice(11,19):'')+'</div></div>'\n}).join('');\n$('scheduledJobs').innerHTML=html\n}).catch(function(e){$('scheduledJobs').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\n// ========== 审计日志 ==========\nfunction loadAuditLogs(){\nvar event=$('auditEventFilter').value;\nvar url='/api/audit/logs?days=30';\nif(event)url+='&event='+event;\napi(url).then(function(data){\nif(data.length===0){$('auditLogsList').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无审计日志</p>';return}\nvar html=data.map(function(log){\nvar time=new Date(log.created_at).toLocaleString();\nvar details=JSON.parse(log.details||'{}');\nvar detailsStr=Object.keys(details).map(function(k){return k+': '+details[k]}).join(', ');\nreturn'<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px;border-left:4px solid var(--accent)\"><div style=\"display:flex;justify-content:space-between;margin-bottom:4px\"><span style=\"font-weight:500\">'+log.action+'</span><span style=\"font-size:12px;color:var(--text2)\">'+time+'</span></div><div style=\"font-size:13px;color:var(--text2)\">用户: '+log.user_id+' | 资源: '+log.resource+'</div>'+(detailsStr?'<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+detailsStr+'</div>':'')+'</div>'\n}).join('');\n$('auditLogsList').innerHTML=html\n}).catch(function(e){$('auditLogsList').innerHTML='<p style=\"color:var(--error);text-align:center;padding:20px\">加载失败: '+e.message+'</p>'})}\n\nfunction exportAuditLogs(){\nif(!confirm('确定导出审计日志?'))return;\napi('/api/audit/export',{method:'POST',body:JSON.stringify({days:30,format:'csv'})}).then(function(data){\nvar blob=new Blob([data.content],{type:'text/csv'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download=data.filename;\na.click();\nshowToast('审计日志已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})}\n\nfunction generateComplianceReport(period){\napi('/api/audit/report?period='+period).then(function(data){\nvar html='<div style=\"padding:20px;background:var(--bg);border-radius:12px\">';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:16px\"><strong>'+period.toUpperCase()+' 合规报告</strong><span style=\"color:var(--text2)\">'+data.generated_at.slice(0,16)+'</span></div>';\nhtml+='<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-bottom:16px\">';\nhtml+='<div style=\"text-align:center\"><div style=\"font-size:24px;font-weight:600;color:var(--accent)\">'+Object.keys(data.event_summary).length+'</div><div style=\"font-size:12px;color:var(--text2)\">事件类型</div></div>';\nhtml+='<div style=\"text-align:center\"><div style=\"font-size:24px;font-weight:600;color:'+(data.security_alerts>0?'var(--error)':'var(--success)')+'\">'+(data.security_alerts||0)+'</div><div style=\"font-size:12px;color:var(--text2)\">安全警报</div></div>';\nhtml+='<div style=\"text-align:center\"><div style=\"font-size:24px;font-weight:600;color:'+(data.compliance_status==='compliant'?'var(--success)':'var(--warning)')+'\">'+(data.compliance_status||'N/A').toUpperCase()+'</div><div style=\"font-size:12px;color:var(--text2)\">合规状态</div></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px\"><strong>事件统计:</strong><div style=\"margin-top:8px\">';\nfor(var event in data.event_summary){\nhtml+='<div style=\"display:flex;justify-content:space-between;padding:4px 0\"><span>'+event+'</span><span>'+data.event_summary[event]+'</span></div>'\n}\nhtml+='</div></div></div>';\n$('complianceReport').innerHTML=html\n}).catch(function(e){$('complianceReport').innerHTML='<p style=\"color:var(--error)\">生成失败: '+e.message+'</p>'})}\n\n// ========== 安全中心 ==========\nfunction loadSecurityStatus(){\napi('/api/security/status').then(function(data){\n$('blockedIpsCount').textContent=data.blocked_ips||0;\n$('failedAttemptsCount').textContent=data.failed_attempts_tracked||0;\n$('twoFaUsersCount').textContent=data['2fa_enabled_users']||0;\nvar score=data.blocked_ips===0&&data.failed_attempts_tracked<10?'A':'B';\n$('securityScore').textContent=score;\n$('securityScore').style.color=score==='A'?'var(--success)':'var(--warning)'\n}).catch(function(e){console.error('加载安全状态失败:',e)})}\n\nfunction unblockIP(){\nvar ip=$('unblockIpInput').value.trim();\nif(!ip){alert('请输入IP地址');return}\nif(!confirm('确定解封 '+ip+'?'))return;\napi('/api/security/unblock-ip',{method:'POST',body:JSON.stringify({ip:ip})}).then(function(){\nshowToast('IP已解封');\n$('unblockIpInput').value='';\nloadSecurityStatus()\n}).catch(function(e){alert('解封失败: '+e.message)})}\n\n// ========== 本地模型 (Ollama) ==========\nfunction loadOllamaModels(){\n$('ollamaStatus').innerHTML='<span style=\"color:var(--text2)\">检查 Ollama 连接...</span>';\napi('/api/ollama/models').then(function(data){\nif(data.error){\n$('ollamaStatus').innerHTML='<span style=\"color:var(--error)\">❌ '+data.error+'</span>';\n$('ollamaModelList').innerHTML='';\n$('ollamaModelSelect').innerHTML='<option>无可用模型</option>';\nreturn}\n$('ollamaStatus').innerHTML='<span style=\"color:var(--success)\">✅ Ollama 已连接,共 '+data.models.length+' 个模型</span>';\nvar html=data.models.map(function(m){\nvar size=(m.size/1024/1024/1024).toFixed(1);\nreturn'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div><strong>'+m.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+size+' GB</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"selectOllamaModel(\\''+m.name+'\\')\">使用</button></div>'\n}).join('');\n$('ollamaModelList').innerHTML=html||'<p style=\"color:var(--text2)\">暂无模型,请先拉取</p>';\nvar selectHtml=data.models.map(function(m){return'<option value=\"'+m.name+'\">'+m.name+'</option>'}).join('');\n$('ollamaModelSelect').innerHTML=selectHtml||'<option>无可用模型</option>'\n}).catch(function(e){$('ollamaStatus').innerHTML='<span style=\"color:var(--error)\">❌ 连接失败</span>'})}\n\nfunction showPullModelModal(){\nvar html='<div class=\"form-group\"><label>模型名称</label><input type=\"text\" id=\"pullModelName\" placeholder=\"llama2, mistral, codellama...\"></div><p style=\"font-size:12px;color:var(--text2);margin-bottom:16px\">常用模型: llama2, mistral, codellama, phi, gemma</p><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"pullOllamaModel()\">拉取</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pullModal\\')\">取消</button></div>';\nshowCustomModal('拉取 Ollama 模型',html,'pullModal')}\n\nfunction pullOllamaModel(){\nvar model=$('pullModelName').value.trim();\nif(!model){alert('请输入模型名称');return}\nshowToast('开始拉取 '+model+',请稍候...');\ncloseModal('pullModal');\napi('/api/ollama/pull',{method:'POST',body:JSON.stringify({model:model})}).then(function(data){\nif(data.success){showToast('模型拉取成功!');loadOllamaModels()}else{alert('拉取失败')}\n}).catch(function(e){alert('拉取失败: '+e.message)})}\n\nfunction selectOllamaModel(name){$('ollamaModelSelect').value=name;showToast('已选择 '+name)}\n\nfunction chatWithOllama(){\nvar model=$('ollamaModelSelect').value;\nvar message=$('ollamaMessage').value.trim();\nif(!model||!message){alert('请选择模型并输入消息');return}\n$('ollamaResponse').style.display='block';\n$('ollamaResponse').innerHTML='<p style=\"color:var(--text2)\">思考中...</p>';\napi('/api/ollama/chat',{method:'POST',body:JSON.stringify({model:model,messages:[{role:'user',content:message}]})}).then(function(data){\nvar content=data.message?data.message.content:'无响应';\n$('ollamaResponse').innerHTML=marked.parse(content)\n}).catch(function(e){$('ollamaResponse').innerHTML='<p style=\"color:var(--error)\">错误: '+e.message+'</p>'})}\n\nfunction loadVLLMModels(){\nvar url=$('vllmUrl').value.trim();\n$('vllmStatus').innerHTML='<span style=\"color:var(--text2)\">检查连接...</span>';\nfetch(url+'/v1/models').then(function(r){return r.json()}).then(function(data){\nif(data.data&&data.data.length>0){\n$('vllmStatus').innerHTML='<span style=\"color:var(--success)\">✅ vLLM 已连接,模型: '+data.data.map(function(m){return m.id}).join(', ')+'</span>'\n}else{\n$('vllmStatus').innerHTML='<span style=\"color:var(--warning)\">⚠️ 已连接但无模型</span>'\n}\n}).catch(function(){$('vllmStatus').innerHTML='<span style=\"color:var(--error)\">❌ 无法连接到 vLLM</span>'})}\n\n// ========== RAG 检索 ==========\nfunction loadRAGKnowledgeBases(){\napi('/api/knowledge-bases').then(function(data){\nvar html='<option value=\"\">选择知识库</option>';\ndata.forEach(function(kb){html+='<option value=\"'+kb.id+'\">'+kb.name+'</option>'});\n$('ragKbSelect').innerHTML=html\n}).catch(function(){})}\n\nfunction searchRAG(){\nvar kbId=$('ragKbSelect').value;\nvar query=$('ragQuery').value.trim();\nif(!kbId){alert('请选择知识库');return}\nif(!query){alert('请输入问题');return}\n$('ragResults').innerHTML='<p style=\"color:var(--text2)\">搜索中...</p>';\napi('/api/rag/search',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),query:query,top_k:5})}).then(function(data){\nif(data.results.length===0){$('ragResults').innerHTML='<p style=\"color:var(--text2)\">未找到相关内容</p>';return}\nvar html=data.results.map(function(r,i){\nreturn'<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px;border-left:4px solid var(--accent)\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span style=\"font-weight:500\">#'+(i+1)+' '+r.chunk_id+'</span><span style=\"color:var(--accent)\">相似度: '+(r.score*100).toFixed(1)+'%</span></div><div style=\"font-size:14px;color:var(--text2);line-height:1.6\">'+r.content.slice(0,300)+(r.content.length>300?'...':'')+'</div></div>'\n}).join('');\n$('ragResults').innerHTML=html\n}).catch(function(e){$('ragResults').innerHTML='<p style=\"color:var(--error)\">搜索失败: '+e.message+'</p>'})}\n\nfunction chatWithRAG(){\nvar kbId=$('ragKbSelect').value;\nvar query=$('ragQuery').value.trim();\nif(!kbId){alert('请选择知识库');return}\nif(!query){alert('请输入问题');return}\n$('ragResults').innerHTML='<p style=\"color:var(--text2)\">AI 正在思考...</p>';\napi('/api/rag/chat',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),question:query})}).then(function(data){\nvar html='<div style=\"padding:20px;background:var(--bg);border-radius:12px\"><div style=\"font-size:14px;line-height:1.8\">'+marked.parse(data.answer)+'</div>';\nif(data.sources&&data.sources.length>0){\nhtml+='<div style=\"margin-top:16px;padding-top:16px;border-top:1px solid var(--border)\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:8px\">参考来源:</div>';\ndata.sources.forEach(function(s){html+='<span class=\"tag\" style=\"margin-right:8px\">'+s.chunk_id+' ('+(s.score*100).toFixed(0)+'%)</span>'});\nhtml+='</div>'}\nhtml+='</div>';\n$('ragResults').innerHTML=html\n}).catch(function(e){$('ragResults').innerHTML='<p style=\"color:var(--error)\">对话失败: '+e.message+'</p>'})}\n\nfunction indexDocument(){\nvar kbId=$('ragKbSelect').value;\nvar content=$('ragContent').value.trim();\nvar filename=$('ragFilename').value.trim()||'document.txt';\nif(!kbId){alert('请选择知识库');return}\nif(!content){alert('请输入文档内容');return}\nshowToast('正在索引文档...');\napi('/api/rag/index',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),content:content,filename:filename})}).then(function(data){\nshowToast('索引完成,共 '+data.indexed_chunks+' 个分块');\n$('ragContent').value='';\n$('ragFilename').value=''\n}).catch(function(e){alert('索引失败: '+e.message)})}\n\n// ========== 计费系统 ==========\nfunction loadBillingPlans(){\napi('/api/billing/plans').then(function(data){\nvar html=data.map(function(p){\nvar features=JSON.parse(p.features||'[]');\nreturn'<div class=\"price-card\" onclick=\"subscribePlan(\\''+p.id+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">¥'+p.price+'<span>/月</span></div><ul>'+features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn btn-primary\" style=\"width:100%\">选择</button></div>'\n}).join('');\n$('billingPlans').innerHTML=html\n}).catch(function(){})}\n\nfunction loadSubscription(){\napi('/api/billing/subscription').then(function(data){\n$('currentPlanName').textContent=data.plan_name||data.plan||'免费版';\nvar remaining=data.tokens_limit===-1?'无限':formatNumber(data.tokens_limit||10000);\n$('remainingQuota').textContent=remaining\n}).catch(function(){})}\n\nfunction loadUsageStats(){\napi('/api/billing/usage?period=month').then(function(data){\nvar html='';\nfor(var type in data.usage){\nvar u=data.usage[type];\nhtml+='<div style=\"padding:16px;background:var(--bg);border-radius:10px;text-align:center\"><div style=\"font-size:24px;font-weight:600;color:var(--accent)\">'+formatNumber(u.amount)+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+type+'</div><div style=\"font-size:11px;color:var(--success);margin-top:4px\">¥'+u.cost.toFixed(2)+'</div></div>'\n}\n$('usageStats').innerHTML=html||'<p style=\"color:var(--text2);grid-column:1/-1;text-align:center\">暂无用量数据</p>'\n}).catch(function(){})}\n\nfunction loadInvoices(){\napi('/api/billing/invoices').then(function(data){\nif(data.length===0){$('invoiceList').innerHTML='<p style=\"color:var(--text2)\">暂无发票</p>';return}\nvar html=data.map(function(inv){\nvar statusColor=inv.status==='paid'?'var(--success)':'var(--warning)';\nreturn'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div><div style=\"font-weight:500\">'+inv.id+'</div><div style=\"font-size:12px;color:var(--text2)\">'+(inv.created_at||'').slice(0,10)+'</div></div><div style=\"text-align:right\"><div style=\"font-weight:600\">¥'+inv.amount+'</div><div style=\"font-size:12px;color:'+statusColor+'\">'+(inv.status==='paid'?'已支付':'待支付')+'</div></div>'+(inv.status!=='paid'?'<button class=\"btn btn-primary btn-sm\" onclick=\"payInvoice(\\''+inv.id+'\\')\">支付</button>':'')+'</div>'\n}).join('');\n$('invoiceList').innerHTML=html\n}).catch(function(){})}\n\nfunction subscribePlan(planId){\nif(!authToken){alert('请先登录');return}\nif(!confirm('确定订阅此套餐?'))return;\napi('/api/billing/subscribe',{method:'POST',body:JSON.stringify({plan_id:planId,months:1})}).then(function(data){\nshowToast('订阅成功,请支付发票');\nloadInvoices();\nloadSubscription()\n}).catch(function(e){alert('订阅失败: '+e.message)})}\n\nfunction payInvoice(invoiceId){\nif(!confirm('确定支付?'))return;\napi('/api/billing/pay/'+invoiceId,{method:'POST',body:JSON.stringify({method:'alipay'})}).then(function(){\nshowToast('支付成功!');\nloadInvoices();\nloadSubscription()\n}).catch(function(e){alert('支付失败: '+e.message)})}\n\n// ========== RBAC 权限 ==========\nfunction loadMyPermissions(){\napi('/api/rbac/my-permissions').then(function(data){\nvar html=data.permissions.map(function(p){\nreturn'<span class=\"tag tag-primary\">'+p+'</span>'\n}).join('');\n$('myPermissions').innerHTML=html||'<span style=\"color:var(--text2)\">暂无权限</span>'\n}).catch(function(){})}\n\nfunction loadRoles(){\napi('/api/rbac/roles').then(function(data){\nvar html=data.map(function(r){\nvar perms=JSON.parse(r.permissions||'[]');\nreturn'<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong>'+r.name+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.description+'</span></div><div style=\"display:flex;flex-wrap:wrap;gap:6px\">'+perms.map(function(p){return'<span class=\"tag\">'+p+'</span>'}).join('')+'</div></div>'\n}).join('');\n$('rolesList').innerHTML=html\n}).catch(function(){})}\n\nfunction showCreateRoleModal(){\nvar html='<div class=\"form-group\"><label>角色名称</label><input type=\"text\" id=\"newRoleName\" placeholder=\"role_name\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"newRoleDesc\" placeholder=\"角色描述\"></div><div class=\"form-group\"><label>权限(逗号分隔)</label><input type=\"text\" id=\"newRolePerms\" placeholder=\"chat,notes,memory\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createRole()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'roleModal\\')\">取消</button></div>';\nshowCustomModal('创建角色',html,'roleModal')}\n\nfunction createRole(){\nvar name=$('newRoleName').value.trim();\nvar desc=$('newRoleDesc').value.trim();\nvar perms=$('newRolePerms').value.split(',').map(function(p){return p.trim()}).filter(function(p){return p});\nif(!name){alert('请输入角色名称');return}\napi('/api/rbac/roles',{method:'POST',body:JSON.stringify({name:name,description:desc,permissions:perms})}).then(function(){\ncloseModal('roleModal');\nloadRoles();\nshowToast('角色已创建')\n}).catch(function(e){alert('创建失败: '+e.message)})}\n\n// 初始化时加载推荐\nsetTimeout(loadRecommendations,1000);\nsetTimeout(loadIntegrations,100);\n\n// ========== 快捷键帮助 ==========\nfunction showHotkeyHelp(){\nvar html='<div style=\"display:grid;gap:8px\">';\nvar hotkeys=[\n['Ctrl + N','新建对话'],\n['Ctrl + K','全局搜索'],\n['Ctrl + D','切换主题'],\n['Ctrl + H','系统状态'],\n['Ctrl + B','批量选择'],\n['Ctrl + F','搜索当前对话'],\n['Ctrl + /','快捷键帮助'],\n['Enter','发送消息'],\n['Shift + Enter','换行'],\n['Escape','关闭弹窗']\n];\nhotkeys.forEach(function(h){\nhtml+='<div class=\"hotkey-help-item\"><span>'+h[1]+'</span><span class=\"hotkey-help-key\">'+h[0]+'</span></div>'\n});\nhtml+='</div>';\nshowCustomModal('⌨️ 快捷键帮助',html,'hotkeyHelpModal')}\n\n// ========== 欢迎引导 ==========\nfunction showWelcomeGuide(){\nif(localStorage.getItem('welcomeShown'))return;\nvar html='<div style=\"text-align:center;padding:20px\"><div style=\"font-size:48px;margin-bottom:16px\">🤖</div><h2 style=\"margin-bottom:12px\">欢迎使用 AI Hub</h2><p style=\"color:var(--text2);margin-bottom:24px\">一站式 AI 平台,支持多模型、多功能</p><div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:12px;text-align:left;margin-bottom:24px\"><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">💬</span><div style=\"font-weight:500;margin-top:8px\">多模型对话</div><div style=\"font-size:12px;color:var(--text2)\">支持 OpenAI、Claude、Gemini 等</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">🎨</span><div style=\"font-weight:500;margin-top:8px\">图片生成</div><div style=\"font-size:12px;color:var(--text2)\">DALL-E 3 AI 绘图</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">📚</span><div style=\"font-weight:500;margin-top:8px\">知识库</div><div style=\"font-size:12px;color:var(--text2)\">上传文档,智能问答</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">👥</span><div style=\"font-weight:500;margin-top:8px\">团队协作</div><div style=\"font-size:12px;color:var(--text2)\">多人共享对话和资源</div></div></div><button class=\"btn btn-primary\" onclick=\"closeModal(\\'welcomeModal\\');localStorage.setItem(\\'welcomeShown\\',\\'1\\')\">开始使用</button></div>';\nshowCustomModal('',html,'welcomeModal')}\nsetTimeout(showWelcomeGuide,500);\n\nconsole.log('🤖 AI Hub v2.0.0 - Enhanced');\n</script>\n</body>\n</html>\n"}, "a2fbd2351cd943dde620e3c7f8da1bdd494c10ae": {"t": 1785765455.3684115, "n": 261049, "h": "8b1dbf1ceaf51cb1", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"theme-color\" content=\"#0f0f1a\">\n<meta name=\"description\" content=\"AI Hub - 统一 AI 平台\">\n<link rel=\"manifest\" href=\"/static/manifest.json\">\n<link rel=\"apple-touch-icon\" href=\"/static/icon-192.png\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0;overflow-y:auto;overflow-x:hidden}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px;flex:1;overflow-y:auto}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"local-models\"><span class=\"nav-item-icon\">🏠</span> 本地模型</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"traces\"><span class=\"nav-item-icon\">🔍</span> 链路追踪</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n<div class=\"nav-item\" data-page=\"rag\"><span class=\"nav-item-icon\">🔍</span> RAG 检索</div>\n<div class=\"nav-item\" data-page=\"billing\"><span class=\"nav-item-icon\">💳</span> 订阅计费</div>\n<div class=\"nav-item\" data-page=\"rbac\"><span class=\"nav-item-icon\">🛡️</span> 权限管理</div>\n<div class=\"nav-item\" data-page=\"audit\"><span class=\"nav-item-icon\">📜</span> 审计日志</div>\n<div class=\"nav-item\" data-page=\"security\"><span class=\"nav-item-icon\">🔒</span> 安全中心</div>\n<div class=\"nav-item\" data-page=\"monitoring\"><span class=\"nav-item-icon\">📊</span> 系统监控</div>\n<div class=\"nav-item\" data-page=\"tasks\"><span class=\"nav-item-icon\">⚙️</span> 任务队列</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"integrations\"><span class=\"nav-item-icon\">🔗</span> 第三方集成</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"workflows\"><span class=\"nav-item-icon\">🤖</span> Agent 工作流</div>\n<div class=\"nav-item\" data-page=\"code-runner\"><span class=\"nav-item-icon\">▶️</span> 代码运行</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" onclick=\"showHealthDashboard()\"><span class=\"nav-item-icon\">🖥️</span> 系统状态</div>\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\" title=\"批量操作\">☑️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div id=\"batchActions\" style=\"display:none;padding:8px;background:var(--bg3);gap:8px;align-items:center\">\n<span style=\"font-size:12px\">已选 <span id=\"selectedCount\">0</span> 个</span>\n<button class=\"btn btn-danger btn-sm\" onclick=\"batchDeleteChats()\">删除</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"batchExportChats()\">导出</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\">取消</button>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"quickReplies\" style=\"display:none;padding:8px 0;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap\"></div>\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateImage()\" title=\"生成图片\">🎨</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateMindmap()\" title=\"生成思维导图\">🧠</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"saveAsTemplate()\" title=\"保存为模板\">💾</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 本地模型页 -->\n<div id=\"page-local-models\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🏠</span> 本地模型 (Ollama)</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">使用 Ollama 运行本地大语言模型,数据完全私有</p>\n<div style=\"display:flex;gap:12px;margin-bottom:20px\">\n<button class=\"btn btn-primary\" onclick=\"loadOllamaModels()\">🔄 刷新模型</button>\n<button class=\"btn btn-ghost\" onclick=\"showPullModelModal()\">📥 拉取模型</button>\n<a href=\"https://ollama.ai\" target=\"_blank\" class=\"btn btn-ghost\">📖 Ollama 官网</a>\n</div>\n<div id=\"ollamaStatus\" style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:16px\"></div>\n<div id=\"ollamaModelList\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 本地模型对话</h4>\n<div class=\"form-group\"><label>选择模型</label><select id=\"ollamaModelSelect\" style=\"width:100%;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select></div>\n<div class=\"form-group\"><label>消息</label><textarea id=\"ollamaMessage\" rows=\"4\" placeholder=\"输入消息...\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"chatWithOllama()\">发送</button>\n<div id=\"ollamaResponse\" style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:8px;min-height:100px;display:none\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚡</span> vLLM 服务</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">高性能推理服务器</p>\n<div class=\"form-group\"><label>vLLM 地址</label><input type=\"text\" id=\"vllmUrl\" value=\"http://localhost:8080\" placeholder=\"http://localhost:8080\"></div>\n<button class=\"btn btn-ghost\" onclick=\"loadVLLMModels()\">检查连接</button>\n<div id=\"vllmStatus\" style=\"margin-top:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">双因素认证 (2FA)<br><small style=\"color:var(--text2)\">使用 Google Authenticator 等应用增强账户安全</small></div><div style=\"display:flex;gap:8px\"><span id=\"2faStatus\" style=\"color:var(--text2)\">未启用</span><button class=\"btn btn-ghost btn-sm\" onclick=\"setup2FA()\" id=\"2faBtn\">设置</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录设备管理</div><button class=\"btn btn-ghost btn-sm\" onclick=\"alert('功能开发中')\">查看设备</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">修改密码</div><button class=\"btn btn-ghost btn-sm\" onclick=\"showChangePasswordModal()\">修改</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复<br><small style=\"color:var(--text2)\">导出/导入所有数据(对话、笔记、记忆、设置)</small></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-primary\" onclick=\"exportAllData()\">📤 导出全部</button><button class=\"btn btn-ghost\" onclick=\"importAllData()\">📥 导入数据</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据库优化<br><small style=\"color:var(--text2)\">清理过期数据,优化数据库性能</small></div><button class=\"btn btn-ghost\" onclick=\"optimizeDatabase()\">🔧 优化数据库</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n<button class=\"btn btn-primary\" onclick=\"showUsageAnalytics()\">📈 详细分析</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 链路追踪页 -->\n<div id=\"page-traces\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔍</span> 链路追踪</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"loadTraces()\">🔄 刷新</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportTraces()\">📥 导出</button>\n</div>\n</div>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:20px\">监控 API 请求的完整调用链路,分析性能瓶颈</p>\n<div id=\"tracesList\"><p style=\"color:var(--text2)\">点击刷新加载追踪记录</p></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 性能概览</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--accent)\" id=\"traceAvgLatency\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">平均延迟</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--success)\" id=\"traceSuccessRate\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">成功率</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--warning)\" id=\"traceCount\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总追踪数</div>\n</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- RAG 检索页 -->\n<div id=\"page-rag\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> RAG 语义检索</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">基于向量的语义搜索,让 AI 理解你的文档内容</p>\n<div class=\"form-group\"><label>选择知识库</label><select id=\"ragKbSelect\" style=\"width:100%;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select></div>\n<div class=\"form-group\"><label>搜索问题</label><input type=\"text\" id=\"ragQuery\" placeholder=\"输入你的问题...\"></div>\n<button class=\"btn btn-primary\" onclick=\"searchRAG()\">🔍 语义搜索</button>\n<button class=\"btn btn-ghost\" onclick=\"chatWithRAG()\" style=\"margin-left:8px\">💬 RAG 对话</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 搜索结果</h4>\n<div id=\"ragResults\" style=\"min-height:100px\"><p style=\"color:var(--text2)\">输入问题后点击搜索</p></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📤</span> 索引文档</h4>\n<div class=\"form-group\"><label>文档内容</label><textarea id=\"ragContent\" rows=\"6\" placeholder=\"粘贴文档内容...\"></textarea></div>\n<div class=\"form-group\"><label>文件名</label><input type=\"text\" id=\"ragFilename\" placeholder=\"document.txt\"></div>\n<button class=\"btn btn-primary\" onclick=\"indexDocument()\">📥 索引文档</button>\n</div>\n</div></div></div></div>\n<!-- 订阅计费页 -->\n<div id=\"page-billing\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💳</span> 订阅计费</h4>\n<div id=\"currentSubscription\" style=\"padding:20px;background:var(--bg);border-radius:12px;margin-bottom:20px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div><div style=\"font-size:12px;color:var(--text2)\">当前套餐</div><div style=\"font-size:24px;font-weight:600\" id=\"currentPlanName\">免费版</div></div>\n<div style=\"text-align:right\"><div style=\"font-size:12px;color:var(--text2)\">剩余额度</div><div style=\"font-size:24px;font-weight:600;color:var(--accent)\" id=\"remainingQuota\">10,000</div></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 套餐选择</h4>\n<div id=\"billingPlans\" class=\"price-cards\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 用量统计</h4>\n<div id=\"usageStats\" style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🧾</span> 发票记录</h4>\n<div id=\"invoiceList\"></div>\n</div>\n</div></div></div></div>\n<!-- 权限管理页 -->\n<div id=\"page-rbac\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🛡️</span> 权限管理</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">基于角色的访问控制 (RBAC)</p>\n<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<div style=\"font-size:12px;color:var(--text2);margin-bottom:8px\">我的权限</div>\n<div id=\"myPermissions\" style=\"display:flex;flex-wrap:wrap;gap:8px\"></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👥</span> 角色列表</h4>\n<div id=\"rolesList\"></div>\n<button class=\"btn btn-ghost\" onclick=\"showCreateRoleModal()\" style=\"margin-top:12px\">+ 创建角色</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> 权限说明</h4>\n<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:12px;font-size:13px\">\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>chat</strong> - 对话功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>notes</strong> - 笔记功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>memory</strong> - 全局记忆</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>image</strong> - 图片生成</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>code</strong> - 代码运行</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>rag</strong> - RAG 检索</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>admin</strong> - 管理功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>*</strong> - 所有权限</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 审计日志页 -->\n<div id=\"page-audit\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📜</span> 审计日志</h4>\n<div style=\"display:flex;gap:8px\">\n<select id=\"auditEventFilter\" style=\"padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\" onchange=\"loadAuditLogs()\">\n<option value=\"\">全部事件</option>\n<option value=\"user.login\">用户登录</option>\n<option value=\"data.export\">数据导出</option>\n<option value=\"settings.change\">设置变更</option>\n<option value=\"payment.create\">支付创建</option>\n<option value=\"security.alert\">安全警报</option>\n</select>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"loadAuditLogs()\">🔄 刷新</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportAuditLogs()\">📥 导出</button>\n</div>\n</div>\n<div id=\"auditLogsList\" style=\"max-height:400px;overflow-y:auto\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 合规报告</h4>\n<div style=\"display:flex;gap:12px;margin-bottom:16px\">\n<button class=\"btn btn-primary\" onclick=\"generateComplianceReport('month')\">月度报告</button>\n<button class=\"btn btn-ghost\" onclick=\"generateComplianceReport('quarter')\">季度报告</button>\n<button class=\"btn btn-ghost\" onclick=\"generateComplianceReport('year')\">年度报告</button>\n</div>\n<div id=\"complianceReport\"></div>\n</div>\n</div></div></div></div>\n<!-- 安全中心页 -->\n<div id=\"page-security\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔒</span> 安全中心</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:20px\">\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"blockedIpsCount\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">封禁 IP</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"failedAttemptsCount\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">失败尝试</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"twoFaUsersCount\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">2FA 用户</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"securityScore\">A</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">安全评分</div>\n</div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"loadSecurityStatus()\">🔄 刷新状态</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> IP 封禁管理</h4>\n<div class=\"form-group\"><label>解封 IP</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"unblockIpInput\" placeholder=\"192.168.1.1\"><button class=\"btn btn-ghost\" onclick=\"unblockIP()\">解封</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">强制密码复杂度<br><small style=\"color:var(--text2)\">要求密码包含大小写、数字和特殊字符</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录失败锁定<br><small style=\"color:var(--text2)\">5次失败后锁定1小时</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">会话超时<br><small style=\"color:var(--text2)\">30天无活动自动登出</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 系统监控页 -->\n<div id=\"page-monitoring\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 系统监控</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:20px\">\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"cpuUsage\">0%</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">CPU 使用率</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"memoryUsage\">0%</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">内存使用率</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"diskUsage\">0%</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">磁盘使用率</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--text)\" id=\"uptimeDisplay\">0h</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">运行时间</div>\n</div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"loadSystemMetrics()\">🔄 刷新指标</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 性能指标</h4>\n<div id=\"performanceMetrics\" style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 告警列表</h4>\n<div id=\"alertsList\" style=\"max-height:300px;overflow-y:auto\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> 链路追踪</h4>\n<div id=\"tracesList\" style=\"max-height:300px;overflow-y:auto\"></div>\n</div>\n</div></div></div></div>\n<!-- 任务队列页 -->\n<div id=\"page-tasks\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 任务队列</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:20px\">\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"pendingTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">待处理</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"runningTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">运行中</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"completedTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">已完成</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"failedTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">失败</div>\n</div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"loadTaskQueue()\">🔄 刷新队列</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 任务列表</h4>\n<div id=\"tasksList\" style=\"max-height:400px;overflow-y:auto\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⏰</span> 定时任务</h4>\n<div id=\"scheduledJobs\" style=\"max-height:300px;overflow-y:auto\"></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- 第三方集成页 -->\n<div id=\"page-integrations\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔗</span> 第三方集成</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:20px\">连接 Slack、飞书等平台,让 AI 助手无处不在</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> Slack 集成</h4>\n<div class=\"form-group\"><label>Bot Token</label><input type=\"password\" id=\"slackToken\" placeholder=\"xoxb-...\" onchange=\"saveIntegration('slack')\"></div>\n<div class=\"form-group\"><label>Signing Secret</label><input type=\"password\" id=\"slackSecret\" placeholder=\"签名密钥\" onchange=\"saveIntegration('slack')\"></div>\n<div class=\"form-group\"><label>Webhook URL</label><div style=\"display:flex;gap:8px\"><input type=\"text\" value=\"http://localhost:8000/api/integrations/slack/webhook\" readonly style=\"flex:1;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText(this.previousElementSibling.value)\">📋</button></div></div>\n<div style=\"display:flex;gap:12px;margin-top:16px\">\n<button class=\"btn btn-primary\" onclick=\"testSlackIntegration()\">🧪 测试连接</button>\n<button class=\"btn btn-ghost\" onclick=\"window.open('https://api.slack.com/apps','_blank')\">📖 创建 Slack App</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐦</span> 飞书集成</h4>\n<div class=\"form-group\"><label>App ID</label><input type=\"text\" id=\"feishuAppId\" placeholder=\"cli_...\" onchange=\"saveIntegration('feishu')\"></div>\n<div class=\"form-group\"><label>App Secret</label><input type=\"password\" id=\"feishuSecret\" placeholder=\"应用密钥\" onchange=\"saveIntegration('feishu')\"></div>\n<div class=\"form-group\"><label>Webhook URL</label><div style=\"display:flex;gap:8px\"><input type=\"text\" value=\"http://localhost:8000/api/integrations/feishu/webhook\" readonly style=\"flex:1;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText(this.previousElementSibling.value)\">📋</button></div></div>\n<div style=\"display:flex;gap:12px;margin-top:16px\">\n<button class=\"btn btn-primary\" onclick=\"testFeishuIntegration()\">🧪 测试连接</button>\n<button class=\"btn btn-ghost\" onclick=\"window.open('https://open.feishu.cn/app','_blank')\">📖 创建飞书应用</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> Webhook 通知</h4>\n<div class=\"form-group\"><label>通知 URL</label><input type=\"text\" id=\"webhookUrl\" placeholder=\"https://your-server.com/webhook\" onchange=\"saveIntegration('webhook')\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">新消息通知</div><label class=\"switch\"><input type=\"checkbox\" id=\"webhookNewMsg\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">错误通知</div><label class=\"switch\"><input type=\"checkbox\" id=\"webhookError\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🎛️</span> 灰度发布</h4>\n<div id=\"featureFlagsList\"></div>\n<button class=\"btn btn-ghost\" onclick=\"loadFeatureFlags()\" style=\"margin-top:12px\">🔄 刷新</button>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Agent 工作流页 -->\n<div id=\"page-workflows\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🤖</span> Agent 工作流</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建多步骤自动化任务,让 AI 按流程完成复杂工作</p>\n<div id=\"workflowTemplates\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👥</span> 多 Agent 协作</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">多个 AI Agent 协同完成复杂任务</p>\n<div class=\"form-group\"><label>任务描述</label><textarea id=\"multiAgentTask\" rows=\"3\" placeholder=\"描述你需要完成的任务...\"></textarea></div>\n<div class=\"form-group\"><label>选择 Agent</label>\n<div id=\"agentCheckboxes\" style=\"display:flex;flex-wrap:wrap;gap:12px\"></div>\n</div>\n<div class=\"form-group\"><label>协作模式</label>\n<select id=\"agentMode\" style=\"width:200px;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\">\n<option value=\"sequential\">顺序执行</option>\n<option value=\"parallel\">并行执行</option>\n<option value=\"debate\">辩论模式</option>\n</select>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runMultiAgent()\">🚀 开始协作</button>\n<button class=\"btn btn-ghost\" onclick=\"showCreateAgentModal()\" style=\"margin-left:8px\">+ 创建 Agent</button>\n</div>\n<div class=\"settings-section\" id=\"multiAgentResults\" style=\"display:none\">\n<h4><span>📋</span> 协作结果</h4>\n<div id=\"multiAgentResultsContent\"></div>\n</div>\n<div class=\"settings-section\" id=\"workflowRunner\" style=\"display:none\">\n<h4><span>▶️</span> 运行工作流</h4>\n<div id=\"workflowInputs\"></div>\n<button class=\"btn btn-primary\" onclick=\"executeWorkflow()\">🚀 执行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('workflowRunner').style.display='none'\">取消</button>\n</div>\n<div class=\"settings-section\" id=\"workflowResults\" style=\"display:none\">\n<h4><span>📋</span> 执行结果</h4>\n<div id=\"workflowResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 代码运行器页 -->\n<div id=\"page-code-runner\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>▶️</span> 代码运行器</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">在线运行 Python / JavaScript 代码</p>\n<div class=\"form-group\">\n<label>语言</label>\n<select id=\"codeLanguage\" style=\"width:150px\">\n<option value=\"python\">Python</option>\n<option value=\"javascript\">JavaScript</option>\n</select>\n</div>\n<div class=\"form-group\">\n<label>代码</label>\n<textarea id=\"codeInput\" rows=\"12\" style=\"font-family:monospace;font-size:13px\" placeholder=\"# 输入代码...\nprint('Hello, World!')\"></textarea>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-primary\" onclick=\"runCode()\">▶️ 运行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('codeInput').value=''\">清空</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 输出结果</h4>\n<pre id=\"codeOutput\" style=\"background:var(--bg);padding:16px;border-radius:8px;min-height:100px;font-family:monospace;font-size:13px;white-space:pre-wrap\">等待运行...</pre>\n</div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>系统状态</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + H</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量选择模式</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + B</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量导出</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>搜索当前对话</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + F</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换主题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + D</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><div class=\"form-group\" id=\"auth2FAGroup\" style=\"display:none\"><label>2FA 验证码</label><input type=\"text\" id=\"auth2FACode\" placeholder=\"6位验证码\" maxlength=\"6\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><div style=\"display:flex;align-items:center;margin:16px 0\"><div style=\"flex:1;height:1px;background:var(--border)\"></div><span style=\"padding:0 12px;color:var(--text2);font-size:12px\">或</span><div style=\"flex:1;height:1px;background:var(--border)\"></div></div><button class=\"btn btn-ghost\" style=\"width:100%;display:flex;align-items:center;justify-content:center;gap:8px\" onclick=\"loginWithGithub()\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg> 使用 GitHub 登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();if(n.dataset.page==='workflows')loadWorkflowTemplates();if(n.dataset.page==='traces')loadTraces();if(n.dataset.page==='integrations')loadFeatureFlags();if(n.dataset.page==='rag')loadRAGKnowledgeBases();if(n.dataset.page==='billing'){loadBillingPlans();loadSubscription();loadUsageStats();loadInvoices()}if(n.dataset.page==='rbac'){loadMyPermissions();loadRoles()}if(n.dataset.page==='local-models')loadOllamaModels();if(n.dataset.page==='workflows')loadAgents();if(n.dataset.page==='audit')loadAuditLogs();if(n.dataset.page==='security')loadSecurityStatus();if(n.dataset.page==='monitoring'){loadSystemMetrics();loadAlerts();loadTraces()}if(n.dataset.page==='tasks')loadTaskQueue();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{\n// 先显示置顶的对话\nvar pinnedChats=chats.filter(function(c){return c.pinned});\nvar normalChats=chats.filter(function(c){return !c.pinned&&!c.archived});\nif(pinnedChats.length>0){html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2)\">📌 置顶</div>';pinnedChats.forEach(function(c){html+=renderChatItem(c)})}\nif(normalChats.length>0){if(pinnedChats.length>0)html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2);margin-top:8px\">💬 对话</div>';normalChats.forEach(function(c){html+=renderChatItem(c)})}}$('chatList').innerHTML=html}\nfunction renderChatItem(c){var selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';var checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';var pinIcon=c.pinned?'📌':'💬';return'<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" style=\"'+selected+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">'+pinIcon+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"favoriteMessageByIndex('+i+')\" title=\"收藏\">❤️</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll();showQuickReplies()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var chat=chats.find(function(c){return c.id===id});var pinText=chat&&chat.pinned?'📌 取消置顶':'📌 置顶';var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"togglePinChat(\\''+id+'\\')\">'+pinText+'</div><div onclick=\"archiveChat(\\''+id+'\\')\">📦 归档</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction togglePinChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.pinned=!chat.pinned;saveChats();renderChats();showToast(chat.pinned?'已置顶':'已取消置顶');if(authToken){api('/api/conversations/'+id+'/pin',{method:'POST'}).catch(function(){})}}\nfunction archiveChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.archived=true;chats=chats.filter(function(c){return c.id!==id});saveChats();renderChats();showToast('已归档');if(authToken){api('/api/conversations/'+id+'/archive',{method:'POST'}).catch(function(){})}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Agent 工作流\nvar workflowTemplates=[];\nvar currentWorkflow=null;\nfunction loadWorkflowTemplates(){api('/api/workflows/templates').then(function(data){workflowTemplates=data;renderWorkflowTemplates()}).catch(function(e){console.error('加载工作流失败:',e)})}\nfunction renderWorkflowTemplates(){var html=workflowTemplates.map(function(w){return'<div style=\"background:var(--bg);border-radius:12px;padding:20px;cursor:pointer\" onclick=\"selectWorkflow(\\''+w.id+'\\')\"><div style=\"display:flex;align-items:center;gap:12px;margin-bottom:12px\"><span style=\"font-size:24px\">🤖</span><div><strong>'+w.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+w.steps.length+' 个步骤</div></div></div><p style=\"font-size:13px;color:var(--text2);line-height:1.5\">'+w.description+'</p></div>'}).join('');$('workflowTemplates').innerHTML=html||'<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无工作流模板</div>'}\nfunction selectWorkflow(id){currentWorkflow=workflowTemplates.find(function(w){return w.id===id});if(!currentWorkflow)return;var inputs=[];currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')&&inputs.indexOf(key)===-1)inputs.push(key)})}});var html=inputs.map(function(key){return'<div class=\"form-group\"><label>'+key+'</label><textarea id=\"wf_'+key+'\" rows=\"3\" placeholder=\"输入 '+key+'\"></textarea></div>'}).join('');$('workflowInputs').innerHTML='<h5 style=\"margin-bottom:16px\">'+currentWorkflow.name+'</h5>'+html;$('workflowRunner').style.display='block';$('workflowResults').style.display='none'}\nfunction executeWorkflow(){if(!currentWorkflow){alert('请先选择工作流');return}var inputData={};currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')){var el=$('wf_'+key);if(el)inputData[key]=el.value}})}});$('workflowResultsContent').innerHTML='<div style=\"text-align:center;padding:40px\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px;color:var(--text2)\">正在执行工作流...</p></div>';$('workflowResults').style.display='block';api('/api/workflows/run',{method:'POST',body:JSON.stringify({name:currentWorkflow.name,steps:currentWorkflow.steps,input_data:inputData})}).then(function(data){var html='';for(var key in data.results){html+='<div style=\"background:var(--bg);border-radius:10px;padding:16px;margin-bottom:12px\"><div style=\"font-weight:600;margin-bottom:8px;color:var(--accent)\">'+key+'</div><div style=\"font-size:14px;line-height:1.6;white-space:pre-wrap\">'+data.results[key]+'</div></div>'}$('workflowResultsContent').innerHTML=html}).catch(function(e){$('workflowResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">执行失败: '+e.message+'</div>'})}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// GitHub 登录\nfunction loginWithGithub(){window.location.href='/api/auth/github'}\n// 2FA 设置\nfunction setup2FA(){if(!authToken){alert('请先登录');return}api('/api/auth/2fa/setup',{method:'POST'}).then(function(data){var html='<div style=\"text-align:center\"><img src=\"'+data.qr_code+'\" style=\"width:200px;height:200px;border-radius:8px\"><p style=\"margin:16px 0;color:var(--text2);font-size:13px\">使用 Google Authenticator 扫描二维码</p><div class=\"form-group\"><label>输入6位验证码确认</label><input type=\"text\" id=\"verify2FACode\" placeholder=\"000000\" maxlength=\"6\" style=\"text-align:center;font-size:20px;letter-spacing:8px\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"verify2FA()\">确认启用</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'2faModal\\')\">取消</button></div></div>';showCustomModal('设置双因素认证',html,'2faModal')}).catch(function(e){alert('设置失败: '+e.message)})}\nfunction verify2FA(){var code=$('verify2FACode').value.trim();if(code.length!==6){alert('请输入6位验证码');return}api('/api/auth/2fa/verify',{method:'POST',body:JSON.stringify({code:code})}).then(function(data){closeModal('2faModal');$('2faStatus').textContent='已启用';$('2faStatus').style.color='var(--success)';$('2faBtn').textContent='禁用';$('2faBtn').onclick=disable2FA;showToast('2FA 已启用')}).catch(function(e){alert('验证失败: '+e.message)})}\nfunction disable2FA(){var code=prompt('输入6位验证码以禁用 2FA:');if(!code)return;api('/api/auth/2fa/disable',{method:'POST',body:JSON.stringify({code:code})}).then(function(){$('2faStatus').textContent='未启用';$('2faStatus').style.color='var(--text2)';$('2faBtn').textContent='设置';$('2faBtn').onclick=setup2FA;showToast('2FA 已禁用')}).catch(function(e){alert('禁用失败: '+e.message)})}\nfunction showChangePasswordModal(){var html='<div class=\"form-group\"><label>当前密码</label><input type=\"password\" id=\"oldPassword\"></div><div class=\"form-group\"><label>新密码</label><input type=\"password\" id=\"newPassword\"></div><div class=\"form-group\"><label>确认新密码</label><input type=\"password\" id=\"confirmPassword\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"changePassword()\">修改</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pwdModal\\')\">取消</button></div>';showCustomModal('修改密码',html,'pwdModal')}\nfunction changePassword(){var oldPwd=$('oldPassword').value,newPwd=$('newPassword').value,confirmPwd=$('confirmPassword').value;if(!oldPwd||!newPwd){alert('请填写密码');return}if(newPwd!==confirmPwd){alert('两次密码不一致');return}alert('密码修改功能开发中')}\n// 检查 URL 中的 token(OAuth 回调)\n(function(){var params=new URLSearchParams(window.location.search);var token=params.get('token');if(token){localStorage.setItem('token',token);authToken=token;window.history.replaceState({},document.title,'/');checkAuth()}})();\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\n// 代码运行器\nfunction runCode(){var code=$('codeInput').value;var lang=$('codeLanguage').value;if(!code.trim()){alert('请输入代码');return}$('codeOutput').textContent='运行中...';$('codeOutput').style.color='var(--text2)';api('/api/code/run',{method:'POST',body:JSON.stringify({code:code,language:lang,timeout:5})}).then(function(data){if(data.success){$('codeOutput').textContent=data.output||'(无输出)';$('codeOutput').style.color='var(--success)'}else{$('codeOutput').textContent='错误: '+(data.error||'未知错误')+'\\n'+data.output;$('codeOutput').style.color='var(--error)'}}).catch(function(e){$('codeOutput').textContent='请求失败: '+e.message;$('codeOutput').style.color='var(--error)'})}\n// 思维导图\nfunction generateMindmap(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}showToast('正在生成思维导图...');api('/api/mindmap/generate',{method:'POST',body:JSON.stringify({messages:chat.messages,title:chat.title})}).then(function(data){renderMindmap(data.nodes)}).catch(function(e){alert('生成失败: '+e.message)})}\nfunction renderMindmap(nodes){var html='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.8);z-index:2000;display:flex;align-items:center;justify-content:center\" onclick=\"if(event.target===this)this.remove()\"><div style=\"background:var(--bg2);border-radius:16px;padding:24px;max-width:800px;max-height:80vh;overflow:auto\"><h3 style=\"margin-bottom:16px\">🧠 思维导图</h3><div id=\"mindmapContent\" style=\"padding:20px\"></div><button class=\"btn btn-ghost\" onclick=\"this.parentElement.parentElement.remove()\">关闭</button></div></div>';document.body.insertAdjacentHTML('beforeend',html);var content='';function renderNode(node,level){var indent=level*24;content+='<div style=\"margin-left:'+indent+'px;padding:8px 12px;margin-bottom:4px;background:var(--bg'+(level>0?'3':'')+');border-radius:6px;border-left:3px solid var(--accent)\">'+(level>0?'├─ ':'')+node.label+'</div>';if(node.children){node.children.forEach(function(c){renderNode(c,level+1)})}}if(nodes&&nodes.length)renderNode(nodes[0],0);$('mindmapContent').innerHTML=content||'<p style=\"color:var(--text2)\">无法生成思维导图</p>'}\n// 保存对话为模板\nfunction saveAsTemplate(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}var name=prompt('模板名称:',chat.title);if(!name)return;api('/api/chat-templates',{method:'POST',body:JSON.stringify({name:name,messages:chat.messages})}).then(function(){showToast('已保存为模板')}).catch(function(e){alert('保存失败: '+e.message)})}\n// 用量配额\nfunction loadQuota(){api('/api/quota').then(function(data){var html='<div style=\"margin-bottom:16px\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Token 使用量</span><span>'+formatNumber(data.tokens_used)+' / '+formatNumber(data.tokens_limit)+'</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;overflow:hidden\"><div style=\"background:var(--accent);height:100%;width:'+data.usage_percent+'%\"></div></div></div><p style=\"font-size:12px;color:var(--text2)\">当前套餐: '+data.plan+'</p>';if($('quotaInfo'))$('quotaInfo').innerHTML=html}).catch(function(e){console.error(e)})}\n// PWA 注册\nif('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js').then(function(reg){console.log('SW registered');if('Notification' in window&&Notification.permission==='default'){Notification.requestPermission()}}).catch(function(e){console.error('SW failed:',e)})}\n// 图片生成\nfunction generateImage(){var prompt=prompt('输入图片描述:');if(!prompt)return;showToast('正在生成图片...');api('/api/images/generate',{method:'POST',body:JSON.stringify({prompt:prompt})}).then(function(data){var img='<img src=\"'+data.url+'\" style=\"max-width:100%;border-radius:8px\">';var chat=chats.find(function(c){return c.id===currentChatId});if(chat){chat.messages.push({role:'assistant',content:'![生成的图片]('+data.url+')\\n\\n'+data.revised_prompt});saveChats();renderMessages()}showToast('图片已生成')}).catch(function(e){alert('生成失败: '+e.message)})}\n// TTS 语音合成\nfunction speakText(text){api('/api/audio/tts',{method:'POST',body:JSON.stringify({text:text,voice:'alloy'})}).then(function(data){var audio=new Audio(data.audio);audio.play();showToast('正在播放')}).catch(function(e){if('speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(text);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('TTS 失败: '+e.message)}})}\n// 内容过滤\nfunction filterContent(text){return api('/api/content/filter',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data})}\n// 数据脱敏\nfunction maskData(text){return api('/api/data/mask',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data.masked})}\n// 备份\nfunction createBackup(){api('/api/backup',{method:'POST'}).then(function(data){showToast('备份已创建: '+data.path)}).catch(function(e){alert('备份失败: '+e.message)})}\n// 离线检测\nwindow.addEventListener('online',function(){showToast('网络已恢复')});\nwindow.addEventListener('offline',function(){showToast('网络已断开,部分功能不可用')});\n\n// ========== 性能监控面板 ==========\nfunction showHealthDashboard(){\napi('/api/health/detailed').then(function(data){\nvar html='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">CPU 使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.cpu_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.cpu_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">内存使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.memory_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.memory_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">磁盘使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.disk_percent>90?'var(--error)':'var(--success)')+'\">'+data.system.disk_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">数据库延迟</div><div style=\"font-size:24px;font-weight:600;color:'+(data.components.database.latency_ms>100?'var(--warning)':'var(--success)')+'\">'+data.components.database.latency_ms+'ms</div></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:10px\">';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>缓存</span><span>'+data.components.cache.size+'/'+data.components.cache.max_size+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Redis</span><span style=\"color:'+(data.components.redis.status==='healthy'?'var(--success)':'var(--warning)')+'\">'+data.components.redis.status+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between\"><span>待处理任务</span><span>'+data.components.task_queue.pending_tasks+'</span></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;text-align:center;font-size:12px;color:var(--text2)\">版本 '+data.version+' · 运行时间 '+formatUptime(data.uptime_seconds)+'</div>';\nshowCustomModal('🖥️ 系统状态',html,'healthModal')\n}).catch(function(e){alert('获取状态失败: '+e.message)})}\nfunction formatUptime(seconds){var h=Math.floor(seconds/3600);var m=Math.floor((seconds%3600)/60);return h+'小时'+m+'分钟'}\n\n// ========== 批量操作 ==========\nvar batchMode=false;\nvar selectedChats=[];\nfunction toggleBatchMode(){batchMode=!batchMode;selectedChats=[];if(batchMode){$('batchActions').style.display='flex';showToast('已进入批量选择模式')}else{$('batchActions').style.display='none'}renderChatList()}\nfunction toggleChatSelection(id,e){if(!batchMode)return;e.stopPropagation();var idx=selectedChats.indexOf(id);if(idx>=0){selectedChats.splice(idx,1)}else{selectedChats.push(id)}renderChatList();$('selectedCount').textContent=selectedChats.length}\nfunction batchDeleteChats(){if(selectedChats.length===0){alert('请先选择对话');return}if(!confirm('确定删除 '+selectedChats.length+' 个对话?'))return;api('/api/conversations/batch-delete',{method:'POST',body:JSON.stringify({ids:selectedChats})}).then(function(data){showToast('已删除 '+data.deleted+' 个对话');selectedChats=[];batchMode=false;$('batchActions').style.display='none';loadChats()}).catch(function(e){alert('删除失败: '+e.message)})}\nfunction batchExportChats(){if(selectedChats.length===0){alert('请先选择对话');return}api('/api/messages/batch-export',{method:'POST',body:JSON.stringify({conversation_ids:selectedChats,format:'json'})}).then(function(data){var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='conversations_export.json';a.click();showToast('已导出 '+data.count+' 个对话')}).catch(function(e){alert('导出失败: '+e.message)})}\n\n// ========== 数据库优化 ==========\nfunction optimizeDatabase(){if(!confirm('确定要优化数据库?这将清理过期数据。'))return;showToast('正在优化...');api('/api/admin/optimize-db',{method:'POST'}).then(function(data){showToast(data.message)}).catch(function(e){alert('优化失败: '+e.message)})}\n\n// ========== 快捷键增强 ==========\ndocument.addEventListener('keydown',function(e){\nif(e.ctrlKey&&e.key==='h'){e.preventDefault();showHealthDashboard()}\nif(e.ctrlKey&&e.key==='b'){e.preventDefault();toggleBatchMode()}\nif(e.ctrlKey&&e.shiftKey&&e.key==='E'){e.preventDefault();batchExportChats()}\nif(e.ctrlKey&&e.key==='f'){e.preventDefault();searchInCurrentChat()}\nif(e.ctrlKey&&e.key==='/'||e.key==='?'){e.preventDefault();showHotkeyHelp()}\n});\n\n// ========== 性能优化:虚拟滚动 ==========\nfunction renderChatListVirtual(){\nvar container=$('chatList');\nvar itemHeight=60;\nvar visibleCount=Math.ceil(container.clientHeight/itemHeight)+2;\nvar scrollTop=container.scrollTop;\nvar startIndex=Math.floor(scrollTop/itemHeight);\nvar endIndex=Math.min(startIndex+visibleCount,chats.length);\nvar html='<div style=\"height:'+(startIndex*itemHeight)+'px\"></div>';\nfor(var i=startIndex;i<endIndex;i++){\nvar c=chats[i];\nvar active=c.id===currentChatId?'active':'';\nvar selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';\nvar checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';\nhtml+='<div class=\"sidebar-item '+active+'\" style=\"'+selected+'\" onclick=\"loadChat(\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+c.title+'</div><div class=\"sidebar-item-desc\">'+(c.messages.length||0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" style=\"opacity:0\" onclick=\"deleteChat(\\''+c.id+'\\',event)\">🗑️</button></div>'\n}\nhtml+='<div style=\"height:'+((chats.length-endIndex)*itemHeight)+'px\"></div>';\ncontainer.innerHTML=html}\n\n// ========== 请求重试机制 ==========\nasync function apiWithRetry(url,options,maxRetries=3){\nfor(var i=0;i<maxRetries;i++){\ntry{return await api(url,options)}\ncatch(e){\nif(i===maxRetries-1)throw e;\nawait new Promise(function(r){setTimeout(r,1000*(i+1))});\nconsole.log('Retrying request...',i+1)\n}}}\n\n// ========== 消息队列(离线支持) ==========\nvar offlineQueue=JSON.parse(localStorage.getItem('offlineQueue')||'[]');\nfunction queueOfflineMessage(msg){offlineQueue.push({msg:msg,time:Date.now()});localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))}\nfunction processOfflineQueue(){if(offlineQueue.length===0)return;showToast('正在发送离线消息...');var msg=offlineQueue.shift();localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue));sendMessageInternal(msg.msg).then(function(){processOfflineQueue()}).catch(function(){offlineQueue.unshift(msg);localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))})}\nwindow.addEventListener('online',processOfflineQueue);\n\n// ========== 智能预加载 ==========\nfunction preloadNextChat(){\nvar currentIdx=chats.findIndex(function(c){return c.id===currentChatId});\nif(currentIdx>=0&&currentIdx<chats.length-1){\nvar nextChat=chats[currentIdx+1];\nif(!nextChat.messages||nextChat.messages.length===0){\napi('/api/conversations/'+nextChat.id+'/messages').then(function(msgs){nextChat.messages=msgs})}}}\n\n// ========== 自动保存草稿 ==========\nvar draftTimer=null;\nfunction saveDraft(){var input=$('chatInput').value;if(input&&currentChatId){localStorage.setItem('draft_'+currentChatId,input)}}\nfunction loadDraft(){if(currentChatId){var draft=localStorage.getItem('draft_'+currentChatId);if(draft)$('chatInput').value=draft}}\nfunction clearDraft(){if(currentChatId)localStorage.removeItem('draft_'+currentChatId)}\n$('chatInput').addEventListener('input',function(){clearTimeout(draftTimer);draftTimer=setTimeout(saveDraft,1000)});\n\n// ========== 消息搜索增强 ==========\nfunction searchInCurrentChat(){var q=prompt('在当前对话中搜索:');if(!q)return;var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages)return;var results=chat.messages.filter(function(m){return m.content&&m.content.toLowerCase().includes(q.toLowerCase())});if(results.length===0){alert('未找到匹配消息');return}var html='<div style=\"max-height:400px;overflow-y:auto\">';results.forEach(function(m,i){html+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:4px\">'+(m.role==='user'?'👤 用户':'🤖 助手')+'</div><div style=\"font-size:14px\">'+m.content.slice(0,200)+(m.content.length>200?'...':'')+'</div></div>'});html+='</div>';showCustomModal('搜索结果 ('+results.length+')',html,'searchResultModal')}\n\n// ========== 快速回复 ==========\nvar quickReplies=[\n{id:'continue',text:'继续',prompt:'请继续'},\n{id:'explain',text:'解释',prompt:'请详细解释一下'},\n{id:'example',text:'举例',prompt:'请举个例子'},\n{id:'simplify',text:'简化',prompt:'请用更简单的语言解释'},\n{id:'code',text:'代码',prompt:'请给出代码示例'},\n{id:'summary',text:'总结',prompt:'请总结一下要点'}\n];\nfunction showQuickReplies(){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages||chat.messages.length===0){$('quickReplies').style.display='none';return}\nvar lastMsg=chat.messages[chat.messages.length-1];\nif(lastMsg.role!=='assistant'){$('quickReplies').style.display='none';return}\nvar html=quickReplies.map(function(r){return'<button class=\"btn btn-ghost btn-sm\" onclick=\"sendQuickReply(\\''+r.prompt+'\\')\">'+r.text+'</button>'}).join('');\n$('quickReplies').innerHTML=html;\n$('quickReplies').style.display='flex'}\nfunction sendQuickReply(prompt){$('chatInput').value=prompt;sendMessage()}\n\n// ========== 数据导入导出 ==========\nfunction exportAllData(){\nif(!authToken){alert('请先登录');return}\nshowToast('正在导出数据...');\napi('/api/data/export-all',{method:'POST'}).then(function(data){\nvar blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='ai_hub_backup_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})}\n\nfunction importAllData(){\nif(!authToken){alert('请先登录');return}\nvar input=document.createElement('input');\ninput.type='file';\ninput.accept='.json';\ninput.onchange=function(e){\nvar file=e.target.files[0];\nif(!file)return;\nvar reader=new FileReader();\nreader.onload=function(ev){\ntry{\nvar data=JSON.parse(ev.target.result);\nif(!confirm('确定要导入数据?这将添加 '+\n(data.conversations?data.conversations.length:0)+' 个对话、'+\n(data.notes?data.notes.length:0)+' 个笔记'))return;\napi('/api/data/import',{method:'POST',body:JSON.stringify(data)}).then(function(result){\nshowToast('导入完成: '+result.imported.conversations+' 对话, '+result.imported.notes+' 笔记');\nloadChats()\n}).catch(function(e){alert('导入失败: '+e.message)})\n}catch(e){alert('文件格式错误')}};\nreader.readAsText(file)};\ninput.click()}\n\n// ========== 智能推荐 ==========\nfunction loadRecommendations(){\napi('/api/recommendations').then(function(data){\nif(data.features&&data.features.length>0){\nvar html='<div style=\"padding:16px;background:var(--bg3);border-radius:10px;margin-bottom:16px\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:12px\">💡 推荐功能</div><div style=\"display:flex;gap:12px;flex-wrap:wrap\">';\ndata.features.forEach(function(f){\nhtml+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;cursor:pointer;flex:1;min-width:150px\" onclick=\"showFeatureGuide(\\''+f.name+'\\')\"><span style=\"font-size:20px\">'+f.icon+'</span><div style=\"font-size:14px;font-weight:500;margin-top:8px\">'+f.name+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+f.desc+'</div></div>'});\nhtml+='</div></div>';\nvar container=$('chatMessages');\nif(container&&container.querySelector('.empty-state')){\ncontainer.innerHTML=html+container.innerHTML}}\n}).catch(function(){})}\nfunction showFeatureGuide(name){\nvar guides={\n'知识库':'点击左侧导航的\"知识库\",创建知识库并上传文档,AI 将基于您的资料回答问题。',\n'团队协作':'点击左侧导航的\"团队空间\",创建团队并邀请成员,共享对话和资源。'\n};\nalert(guides[name]||'功能介绍开发中')}\n\n// ========== 收藏消息 ==========\nfunction favoriteMessage(content){\nif(!authToken){alert('请先登录');return}\napi('/api/messages/favorite',{method:'POST',body:JSON.stringify({\nconversation_id:currentChatId,\ncontent:content\n})}).then(function(){showToast('已收藏到记忆')}).catch(function(e){alert('收藏失败: '+e.message)})}\nfunction favoriteMessageByIndex(index){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages[index])return;\nfavoriteMessage(chat.messages[index].content)}\n\n// ========== 使用分析 ==========\nfunction showUsageAnalytics(){\napi('/api/analytics/usage?days=30').then(function(data){\nvar html='<div style=\"margin-bottom:20px\"><h4 style=\"margin-bottom:12px\">📊 30天使用趋势</h4>';\nif(data.daily_usage.length>0){\nvar maxCalls=Math.max.apply(null,data.daily_usage.map(function(d){return d.calls}));\nhtml+='<div style=\"display:flex;align-items:flex-end;gap:4px;height:100px\">';\ndata.daily_usage.forEach(function(d){\nvar height=Math.max(5,(d.calls/maxCalls)*100);\nhtml+='<div style=\"flex:1;background:var(--accent);border-radius:2px 2px 0 0;height:'+height+'px\" title=\"'+d.day+': '+d.calls+'次\"></div>'});\nhtml+='</div>'}\nhtml+='</div>';\nhtml+='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">总调用次数</div><div style=\"font-size:24px;font-weight:600\">'+data.total_calls+'</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">错误率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.error_rate>5?'var(--error)':'var(--success)')+'\">'+data.error_rate+'%</div></div>';\nhtml+='</div>';\nshowCustomModal('📈 使用分析',html,'analyticsModal')\n}).catch(function(e){alert('获取分析失败: '+e.message)})}\n\n// ========== 第三方集成 ==========\nfunction saveIntegration(type){\nvar data={};\nif(type==='slack'){\ndata={slack_token:$('slackToken').value,slack_secret:$('slackSecret').value}\n}else if(type==='feishu'){\ndata={feishu_app_id:$('feishuAppId').value,feishu_secret:$('feishuSecret').value}\n}else if(type==='webhook'){\ndata={webhook_url:$('webhookUrl').value,webhook_new_msg:$('webhookNewMsg').checked,webhook_error:$('webhookError').checked}\n}\nlocalStorage.setItem('integration_'+type,JSON.stringify(data));\nshowToast('配置已保存')}\n\nfunction loadIntegrations(){\ntry{\nvar slack=JSON.parse(localStorage.getItem('integration_slack')||'{}');\nif(slack.slack_token)$('slackToken').value=slack.slack_token;\nif(slack.slack_secret)$('slackSecret').value=slack.slack_secret;\nvar feishu=JSON.parse(localStorage.getItem('integration_feishu')||'{}');\nif(feishu.feishu_app_id)$('feishuAppId').value=feishu.feishu_app_id;\nif(feishu.feishu_secret)$('feishuSecret').value=feishu.feishu_secret;\nvar webhook=JSON.parse(localStorage.getItem('integration_webhook')||'{}');\nif(webhook.webhook_url)$('webhookUrl').value=webhook.webhook_url;\nif(webhook.webhook_new_msg)$('webhookNewMsg').checked=true;\nif(webhook.webhook_error)$('webhookError').checked=true;\n}catch(e){}}\n\nfunction testSlackIntegration(){\nshowToast('测试 Slack 连接...');\napi('/api/integrations/slack/send',{method:'POST',body:JSON.stringify({channel:'#general',text:'AI Hub 测试消息'})}).then(function(data){\nif(data.ok){showToast('Slack 连接成功!')}else{alert('连接失败: '+(data.error||'未知错误'))}\n}).catch(function(e){alert('连接失败: '+e.message)})}\n\nfunction testFeishuIntegration(){\nshowToast('测试飞书连接...');\napi('/api/integrations/feishu/send',{method:'POST',body:JSON.stringify({chat_id:'test',text:'AI Hub 测试消息'})}).then(function(data){\nif(data.code===0){showToast('飞书连接成功!')}else{alert('连接失败: '+(data.msg||'未知错误'))}\n}).catch(function(e){alert('连接失败: '+e.message)})}\n\n// ========== 灰度发布 ==========\nfunction loadFeatureFlags(){\napi('/api/features/all').then(function(data){\nvar html='';\nfor(var name in data){\nvar flag=data[name];\nhtml+='<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\">';\nhtml+='<div><strong>'+name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">灰度比例: '+flag.percentage+'% · 白名单用户: '+(flag.users?flag.users.length:0)+'</div></div>';\nhtml+='<label class=\"switch\"><input type=\"checkbox\" '+(flag.enabled?'checked':'')+' onchange=\"toggleFeatureFlag(\\''+name+'\\',this.checked)\"><span class=\"switch-slider\"></span></label>';\nhtml+='</div>'}\n$('featureFlagsList').innerHTML=html||'<p style=\"color:var(--text2)\">暂无功能开关</p>'\n}).catch(function(e){$('featureFlagsList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction toggleFeatureFlag(name,enabled){\napi('/api/features/'+name,{method:'POST',body:JSON.stringify({enabled:enabled})}).then(function(){\nshowToast(name+(enabled?' 已启用':' 已禁用'))\n}).catch(function(e){alert('操作失败: '+e.message)})}\n\nfunction updateFeatureFlagPercentage(name,percentage){\napi('/api/features/'+name,{method:'POST',body:JSON.stringify({percentage:parseInt(percentage)})}).then(function(){\nshowToast('灰度比例已更新')\n}).catch(function(e){alert('操作失败: '+e.message)})}\n\n// ========== 链路追踪 ==========\nfunction loadTraces(){\napi('/api/traces?limit=50').then(function(data){\nif(data.length===0){$('tracesList').innerHTML='<p style=\"color:var(--text2)\">暂无追踪记录</p>';return}\nvar html='<table style=\"width:100%;border-collapse:collapse;font-size:13px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">ID</th><th style=\"padding:10px\">名称</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">Spans</th></tr>';\ndata.forEach(function(t){\nhtml+='<tr style=\"border-top:1px solid var(--border);cursor:pointer\" onclick=\"showTraceDetail(\\''+t.id+'\\')\">';\nhtml+='<td style=\"padding:10px;font-family:monospace\">'+t.id+'</td>';\nhtml+='<td style=\"padding:10px\">'+t.name+'</td>';\nhtml+='<td style=\"padding:10px;text-align:right\">'+(t.total_duration?(t.total_duration*1000).toFixed(0)+'ms':'-')+'</td>';\nhtml+='<td style=\"padding:10px\">'+(t.spans?t.spans.length:0)+'</td>';\nhtml+='</tr>'});\nhtml+='</table>';\n$('tracesList').innerHTML=html\n}).catch(function(e){$('tracesList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction showTraceDetail(traceId){\napi('/api/traces/'+traceId).then(function(data){\nvar html='<div style=\"margin-bottom:16px\"><strong>Trace ID:</strong> '+data.id+'<br><strong>名称:</strong> '+data.name+'<br><strong>总耗时:</strong> '+(data.total_duration?(data.total_duration*1000).toFixed(0)+'ms':'-')+'</div>';\nif(data.spans&&data.spans.length>0){\nhtml+='<h4 style=\"margin-bottom:12px\">Spans</h4>';\ndata.spans.forEach(function(s,i){\nvar width=Math.min(100,s.duration*100);\nhtml+='<div style=\"margin-bottom:8px\"><div style=\"display:flex;justify-content:space-between;font-size:13px\"><span>'+s.name+'</span><span>'+(s.duration*1000).toFixed(0)+'ms</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;margin-top:4px\"><div style=\"background:var(--accent);height:100%;width:'+width+'%;border-radius:4px\"></div></div></div>'\n})}\nshowCustomModal('🔍 追踪详情',html,'traceDetailModal')\n}).catch(function(e){alert('加载失败: '+e.message)})}\n\nfunction exportTraces(){\napi('/api/traces?limit=100').then(function(data){\nif(data.length===0){alert('暂无追踪记录');return}\nvar traceIds=data.map(function(t){return t.id});\napi('/api/traces/export',{method:'POST',body:JSON.stringify({trace_ids:traceIds,format:'jaeger'})}).then(function(result){\nvar blob=new Blob([JSON.stringify(result.data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='traces_export_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('追踪数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})\n}).catch(function(e){alert('获取追踪失败: '+e.message)})}\n\n// ========== 多 Agent 协作 ==========\nfunction loadAgents(){\napi('/api/agents').then(function(data){\nvar html=data.map(function(a){\nreturn'<label style=\"display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer\"><input type=\"checkbox\" class=\"agent-checkbox\" value=\"'+a.name+'\" checked><span>'+a.name+'</span><span style=\"font-size:11px;color:var(--text2)\">'+a.role+'</span></label>'\n}).join('');\n$('agentCheckboxes').innerHTML=html\n}).catch(function(){})}\n\nfunction runMultiAgent(){\nvar task=$('multiAgentTask').value.trim();\nif(!task){alert('请输入任务描述');return}\nvar agents=[];\ndocument.querySelectorAll('.agent-checkbox:checked').forEach(function(cb){agents.push(cb.value)});\nif(agents.length<2){alert('请至少选择2个Agent');return}\nvar mode=$('agentMode').value;\n$('multiAgentResults').style.display='block';\n$('multiAgentResultsContent').innerHTML='<p style=\"color:var(--text2)\">Agent 正在协作中...</p>';\napi('/api/agents/collaborate',{method:'POST',body:JSON.stringify({task:task,agents:agents,mode:mode})}).then(function(data){\nvar html='<div style=\"font-size:12px;color:var(--text2);margin-bottom:16px\">模式: '+data.mode+'</div>';\nfor(var name in data.results){\nhtml+='<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px;border-left:4px solid var(--accent)\"><div style=\"font-weight:500;margin-bottom:8px\">'+name+'</div><div style=\"font-size:14px;line-height:1.6\">'+marked.parse(data.results[name])+'</div></div>'\n}\n$('multiAgentResultsContent').innerHTML=html\n}).catch(function(e){$('multiAgentResultsContent').innerHTML='<p style=\"color:var(--error)\">执行失败: '+e.message+'</p>'})}\n\nfunction showCreateAgentModal(){\nvar html='<div class=\"form-group\"><label>Agent 名称</label><input type=\"text\" id=\"newAgentName\" placeholder=\"分析师\"></div><div class=\"form-group\"><label>角色描述</label><input type=\"text\" id=\"newAgentRole\" placeholder=\"数据分析专家\"></div><div class=\"form-group\"><label>使用模型</label><input type=\"text\" id=\"newAgentModel\" value=\"gpt-4o-mini\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createAgent()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'agentModal\\')\">取消</button></div>';\nshowCustomModal('创建 Agent',html,'agentModal')}\n\nfunction createAgent(){\nvar name=$('newAgentName').value.trim();\nvar role=$('newAgentRole').value.trim();\nvar model=$('newAgentModel').value.trim()||'gpt-4o-mini';\nif(!name||!role){alert('请填写名称和角色');return}\napi('/api/agents/create',{method:'POST',body:JSON.stringify({name:name,role:role,model:model})}).then(function(){\ncloseModal('agentModal');\nloadAgents();\nshowToast('Agent 已创建')\n}).catch(function(e){alert('创建失败: '+e.message)})}\n\n// ========== 系统监控 ==========\nfunction loadSystemMetrics(){\napi('/api/system/metrics').then(function(data){\n$('cpuUsage').textContent=data.cpu_percent+'%';\n$('cpuUsage').style.color=data.cpu_percent>80?'var(--error)':data.cpu_percent>50?'var(--warning)':'var(--success)';\n$('memoryUsage').textContent=data.memory_percent+'%';\n$('memoryUsage').style.color=data.memory_percent>80?'var(--error)':data.memory_percent>50?'var(--warning)':'var(--success)';\n$('diskUsage').textContent=data.disk_percent+'%';\n$('diskUsage').style.color=data.disk_percent>80?'var(--error)':data.disk_percent>50?'var(--warning)':'var(--success)';\nvar hours=Math.floor(data.uptime/3600);\nvar days=Math.floor(hours/24);\n$('uptimeDisplay').textContent=days>0?days+'d '+hours%24+'h':hours+'h';\n// 性能指标\nvar perfHtml='';\nif(data.performance){\nfor(var name in data.performance){\nvar p=data.performance[name];\nperfHtml+='<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><div style=\"font-weight:500;margin-bottom:8px\">'+name+'</div>';\nperfHtml+='<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:8px;font-size:12px\">';\nperfHtml+='<div>平均: <span style=\"color:var(--accent)\">'+p.avg_ms.toFixed(1)+'ms</span></div>';\nperfHtml+='<div>P99: <span style=\"color:var(--warning)\">'+p.p99_ms.toFixed(1)+'ms</span></div>';\nperfHtml+='<div>调用: <span style=\"color:var(--text2)\">'+p.count+'</span></div>';\nperfHtml+='</div></div>'\n}\n}\n$('performanceMetrics').innerHTML=perfHtml||'<p style=\"color:var(--text2);text-align:center\">暂无性能数据</p>'\n}).catch(function(e){console.error('加载系统指标失败:',e)})}\n\nfunction loadAlerts(){\napi('/api/system/alerts').then(function(data){\nif(data.length===0){$('alertsList').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无告警</p>';return}\nvar html=data.map(function(alert){\nvar color=alert.severity==='critical'?'var(--error)':alert.severity==='warning'?'var(--warning)':'var(--text2)';\nreturn'<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px;border-left:4px solid '+color+'\"><div style=\"display:flex;justify-content:space-between\"><span style=\"font-weight:500\">'+alert.name+'</span><span style=\"font-size:12px;color:var(--text2)\">'+alert.timestamp.slice(11,19)+'</span></div><div style=\"font-size:13px;color:var(--text2);margin-top:4px\">'+alert.message+'</div></div>'\n}).join('');\n$('alertsList').innerHTML=html\n}).catch(function(e){$('alertsList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction loadTraces(){\napi('/api/system/traces?limit=20').then(function(data){\nif(data.length===0){$('tracesList').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无追踪数据</p>';return}\nvar html=data.map(function(trace){\nvar color=trace.status==='OK'?'var(--success)':'var(--error)';\nvar duration=(trace.duration/1000).toFixed(2);\nreturn'<div style=\"padding:10px;background:var(--bg);border-radius:8px;margin-bottom:6px;font-size:13px\"><div style=\"display:flex;justify-content:space-between;align-items:center\"><span style=\"font-weight:500\">'+trace.operationName+'</span><span style=\"color:'+color+'\">'+duration+'ms</span></div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">TraceID: '+trace.traceId.slice(0,8)+'...</div></div>'\n}).join('');\n$('tracesList').innerHTML=html\n}).catch(function(e){$('tracesList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\n// ========== 任务队列 ==========\nfunction loadTaskQueue(){\napi('/api/tasks/stats').then(function(data){\n$('pendingTasks').textContent=data.by_status.pending||0;\n$('runningTasks').textContent=data.by_status.running||0;\n$('completedTasks').textContent=data.by_status.completed||0;\n$('failedTasks').textContent=data.by_status.failed||0;\nloadTasksList();\nloadScheduledJobs()\n}).catch(function(e){console.error('加载任务统计失败:',e)})}\n\nfunction loadTasksList(){\napi('/api/tasks?limit=50').then(function(data){\nif(data.length===0){$('tasksList').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无任务</p>';return}\nvar html=data.map(function(task){\nvar statusColors={pending:'var(--warning)',running:'var(--accent)',completed:'var(--success)',failed:'var(--error)',retrying:'var(--warning)'};\nvar color=statusColors[task.status]||'var(--text2)';\nreturn'<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"display:flex;justify-content:space-between;align-items:center\"><span style=\"font-weight:500\">'+task.name+'</span><span style=\"padding:2px 8px;background:'+color+';color:#fff;border-radius:4px;font-size:11px\">'+task.status+'</span></div><div style=\"font-size:12px;color:var(--text2);margin-top:6px\">ID: '+task.id.slice(0,8)+'... | 创建: '+task.created_at.slice(11,19)+(task.duration_ms?' | 耗时: '+task.duration_ms+'ms':'')+'</div>'+(task.error?'<div style=\"font-size:12px;color:var(--error);margin-top:4px\">错误: '+task.error+'</div>':'')+'</div>'\n}).join('');\n$('tasksList').innerHTML=html\n}).catch(function(e){$('tasksList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction loadScheduledJobs(){\napi('/api/tasks/scheduled').then(function(data){\nif(data.length===0){$('scheduledJobs').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无定时任务</p>';return}\nvar html=data.map(function(job){\nreturn'<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"display:flex;justify-content:space-between;align-items:center\"><span style=\"font-weight:500\">'+job.name+'</span><span style=\"font-size:12px;color:var(--text2)\">间隔: '+(job.interval/60)+'分钟</span></div><div style=\"font-size:12px;color:var(--text2);margin-top:6px\">执行次数: '+job.run_count+' | 错误: '+job.errors+(job.last_run?' | 上次: '+job.last_run.slice(11,19):'')+'</div></div>'\n}).join('');\n$('scheduledJobs').innerHTML=html\n}).catch(function(e){$('scheduledJobs').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\n// ========== 审计日志 ==========\nfunction loadAuditLogs(){\nvar event=$('auditEventFilter').value;\nvar url='/api/audit/logs?days=30';\nif(event)url+='&event='+event;\napi(url).then(function(data){\nif(data.length===0){$('auditLogsList').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无审计日志</p>';return}\nvar html=data.map(function(log){\nvar time=new Date(log.created_at).toLocaleString();\nvar details=JSON.parse(log.details||'{}');\nvar detailsStr=Object.keys(details).map(function(k){return k+': '+details[k]}).join(', ');\nreturn'<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px;border-left:4px solid var(--accent)\"><div style=\"display:flex;justify-content:space-between;margin-bottom:4px\"><span style=\"font-weight:500\">'+log.action+'</span><span style=\"font-size:12px;color:var(--text2)\">'+time+'</span></div><div style=\"font-size:13px;color:var(--text2)\">用户: '+log.user_id+' | 资源: '+log.resource+'</div>'+(detailsStr?'<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+detailsStr+'</div>':'')+'</div>'\n}).join('');\n$('auditLogsList').innerHTML=html\n}).catch(function(e){$('auditLogsList').innerHTML='<p style=\"color:var(--error);text-align:center;padding:20px\">加载失败: '+e.message+'</p>'})}\n\nfunction exportAuditLogs(){\nif(!confirm('确定导出审计日志?'))return;\napi('/api/audit/export',{method:'POST',body:JSON.stringify({days:30,format:'csv'})}).then(function(data){\nvar blob=new Blob([data.content],{type:'text/csv'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download=data.filename;\na.click();\nshowToast('审计日志已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})}\n\nfunction generateComplianceReport(period){\napi('/api/audit/report?period='+period).then(function(data){\nvar html='<div style=\"padding:20px;background:var(--bg);border-radius:12px\">';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:16px\"><strong>'+period.toUpperCase()+' 合规报告</strong><span style=\"color:var(--text2)\">'+data.generated_at.slice(0,16)+'</span></div>';\nhtml+='<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-bottom:16px\">';\nhtml+='<div style=\"text-align:center\"><div style=\"font-size:24px;font-weight:600;color:var(--accent)\">'+Object.keys(data.event_summary).length+'</div><div style=\"font-size:12px;color:var(--text2)\">事件类型</div></div>';\nhtml+='<div style=\"text-align:center\"><div style=\"font-size:24px;font-weight:600;color:'+(data.security_alerts>0?'var(--error)':'var(--success)')+'\">'+(data.security_alerts||0)+'</div><div style=\"font-size:12px;color:var(--text2)\">安全警报</div></div>';\nhtml+='<div style=\"text-align:center\"><div style=\"font-size:24px;font-weight:600;color:'+(data.compliance_status==='compliant'?'var(--success)':'var(--warning)')+'\">'+(data.compliance_status||'N/A').toUpperCase()+'</div><div style=\"font-size:12px;color:var(--text2)\">合规状态</div></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px\"><strong>事件统计:</strong><div style=\"margin-top:8px\">';\nfor(var event in data.event_summary){\nhtml+='<div style=\"display:flex;justify-content:space-between;padding:4px 0\"><span>'+event+'</span><span>'+data.event_summary[event]+'</span></div>'\n}\nhtml+='</div></div></div>';\n$('complianceReport').innerHTML=html\n}).catch(function(e){$('complianceReport').innerHTML='<p style=\"color:var(--error)\">生成失败: '+e.message+'</p>'})}\n\n// ========== 安全中心 ==========\nfunction loadSecurityStatus(){\napi('/api/security/status').then(function(data){\n$('blockedIpsCount').textContent=data.blocked_ips||0;\n$('failedAttemptsCount').textContent=data.failed_attempts_tracked||0;\n$('twoFaUsersCount').textContent=data['2fa_enabled_users']||0;\nvar score=data.blocked_ips===0&&data.failed_attempts_tracked<10?'A':'B';\n$('securityScore').textContent=score;\n$('securityScore').style.color=score==='A'?'var(--success)':'var(--warning)'\n}).catch(function(e){console.error('加载安全状态失败:',e)})}\n\nfunction unblockIP(){\nvar ip=$('unblockIpInput').value.trim();\nif(!ip){alert('请输入IP地址');return}\nif(!confirm('确定解封 '+ip+'?'))return;\napi('/api/security/unblock-ip',{method:'POST',body:JSON.stringify({ip:ip})}).then(function(){\nshowToast('IP已解封');\n$('unblockIpInput').value='';\nloadSecurityStatus()\n}).catch(function(e){alert('解封失败: '+e.message)})}\n\n// ========== 本地模型 (Ollama) ==========\nfunction loadOllamaModels(){\n$('ollamaStatus').innerHTML='<span style=\"color:var(--text2)\">检查 Ollama 连接...</span>';\napi('/api/ollama/models').then(function(data){\nif(data.error){\n$('ollamaStatus').innerHTML='<span style=\"color:var(--error)\">❌ '+data.error+'</span>';\n$('ollamaModelList').innerHTML='';\n$('ollamaModelSelect').innerHTML='<option>无可用模型</option>';\nreturn}\n$('ollamaStatus').innerHTML='<span style=\"color:var(--success)\">✅ Ollama 已连接,共 '+data.models.length+' 个模型</span>';\nvar html=data.models.map(function(m){\nvar size=(m.size/1024/1024/1024).toFixed(1);\nreturn'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div><strong>'+m.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+size+' GB</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"selectOllamaModel(\\''+m.name+'\\')\">使用</button></div>'\n}).join('');\n$('ollamaModelList').innerHTML=html||'<p style=\"color:var(--text2)\">暂无模型,请先拉取</p>';\nvar selectHtml=data.models.map(function(m){return'<option value=\"'+m.name+'\">'+m.name+'</option>'}).join('');\n$('ollamaModelSelect').innerHTML=selectHtml||'<option>无可用模型</option>'\n}).catch(function(e){$('ollamaStatus').innerHTML='<span style=\"color:var(--error)\">❌ 连接失败</span>'})}\n\nfunction showPullModelModal(){\nvar html='<div class=\"form-group\"><label>模型名称</label><input type=\"text\" id=\"pullModelName\" placeholder=\"llama2, mistral, codellama...\"></div><p style=\"font-size:12px;color:var(--text2);margin-bottom:16px\">常用模型: llama2, mistral, codellama, phi, gemma</p><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"pullOllamaModel()\">拉取</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pullModal\\')\">取消</button></div>';\nshowCustomModal('拉取 Ollama 模型',html,'pullModal')}\n\nfunction pullOllamaModel(){\nvar model=$('pullModelName').value.trim();\nif(!model){alert('请输入模型名称');return}\nshowToast('开始拉取 '+model+',请稍候...');\ncloseModal('pullModal');\napi('/api/ollama/pull',{method:'POST',body:JSON.stringify({model:model})}).then(function(data){\nif(data.success){showToast('模型拉取成功!');loadOllamaModels()}else{alert('拉取失败')}\n}).catch(function(e){alert('拉取失败: '+e.message)})}\n\nfunction selectOllamaModel(name){$('ollamaModelSelect').value=name;showToast('已选择 '+name)}\n\nfunction chatWithOllama(){\nvar model=$('ollamaModelSelect').value;\nvar message=$('ollamaMessage').value.trim();\nif(!model||!message){alert('请选择模型并输入消息');return}\n$('ollamaResponse').style.display='block';\n$('ollamaResponse').innerHTML='<p style=\"color:var(--text2)\">思考中...</p>';\napi('/api/ollama/chat',{method:'POST',body:JSON.stringify({model:model,messages:[{role:'user',content:message}]})}).then(function(data){\nvar content=data.message?data.message.content:'无响应';\n$('ollamaResponse').innerHTML=marked.parse(content)\n}).catch(function(e){$('ollamaResponse').innerHTML='<p style=\"color:var(--error)\">错误: '+e.message+'</p>'})}\n\nfunction loadVLLMModels(){\nvar url=$('vllmUrl').value.trim();\n$('vllmStatus').innerHTML='<span style=\"color:var(--text2)\">检查连接...</span>';\nfetch(url+'/v1/models').then(function(r){return r.json()}).then(function(data){\nif(data.data&&data.data.length>0){\n$('vllmStatus').innerHTML='<span style=\"color:var(--success)\">✅ vLLM 已连接,模型: '+data.data.map(function(m){return m.id}).join(', ')+'</span>'\n}else{\n$('vllmStatus').innerHTML='<span style=\"color:var(--warning)\">⚠️ 已连接但无模型</span>'\n}\n}).catch(function(){$('vllmStatus').innerHTML='<span style=\"color:var(--error)\">❌ 无法连接到 vLLM</span>'})}\n\n// ========== RAG 检索 ==========\nfunction loadRAGKnowledgeBases(){\napi('/api/knowledge-bases').then(function(data){\nvar html='<option value=\"\">选择知识库</option>';\ndata.forEach(function(kb){html+='<option value=\"'+kb.id+'\">'+kb.name+'</option>'});\n$('ragKbSelect').innerHTML=html\n}).catch(function(){})}\n\nfunction searchRAG(){\nvar kbId=$('ragKbSelect').value;\nvar query=$('ragQuery').value.trim();\nif(!kbId){alert('请选择知识库');return}\nif(!query){alert('请输入问题');return}\n$('ragResults').innerHTML='<p style=\"color:var(--text2)\">搜索中...</p>';\napi('/api/rag/search',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),query:query,top_k:5})}).then(function(data){\nif(data.results.length===0){$('ragResults').innerHTML='<p style=\"color:var(--text2)\">未找到相关内容</p>';return}\nvar html=data.results.map(function(r,i){\nreturn'<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px;border-left:4px solid var(--accent)\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span style=\"font-weight:500\">#'+(i+1)+' '+r.chunk_id+'</span><span style=\"color:var(--accent)\">相似度: '+(r.score*100).toFixed(1)+'%</span></div><div style=\"font-size:14px;color:var(--text2);line-height:1.6\">'+r.content.slice(0,300)+(r.content.length>300?'...':'')+'</div></div>'\n}).join('');\n$('ragResults').innerHTML=html\n}).catch(function(e){$('ragResults').innerHTML='<p style=\"color:var(--error)\">搜索失败: '+e.message+'</p>'})}\n\nfunction chatWithRAG(){\nvar kbId=$('ragKbSelect').value;\nvar query=$('ragQuery').value.trim();\nif(!kbId){alert('请选择知识库');return}\nif(!query){alert('请输入问题');return}\n$('ragResults').innerHTML='<p style=\"color:var(--text2)\">AI 正在思考...</p>';\napi('/api/rag/chat',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),question:query})}).then(function(data){\nvar html='<div style=\"padding:20px;background:var(--bg);border-radius:12px\"><div style=\"font-size:14px;line-height:1.8\">'+marked.parse(data.answer)+'</div>';\nif(data.sources&&data.sources.length>0){\nhtml+='<div style=\"margin-top:16px;padding-top:16px;border-top:1px solid var(--border)\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:8px\">参考来源:</div>';\ndata.sources.forEach(function(s){html+='<span class=\"tag\" style=\"margin-right:8px\">'+s.chunk_id+' ('+(s.score*100).toFixed(0)+'%)</span>'});\nhtml+='</div>'}\nhtml+='</div>';\n$('ragResults').innerHTML=html\n}).catch(function(e){$('ragResults').innerHTML='<p style=\"color:var(--error)\">对话失败: '+e.message+'</p>'})}\n\nfunction indexDocument(){\nvar kbId=$('ragKbSelect').value;\nvar content=$('ragContent').value.trim();\nvar filename=$('ragFilename').value.trim()||'document.txt';\nif(!kbId){alert('请选择知识库');return}\nif(!content){alert('请输入文档内容');return}\nshowToast('正在索引文档...');\napi('/api/rag/index',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),content:content,filename:filename})}).then(function(data){\nshowToast('索引完成,共 '+data.indexed_chunks+' 个分块');\n$('ragContent').value='';\n$('ragFilename').value=''\n}).catch(function(e){alert('索引失败: '+e.message)})}\n\n// ========== 计费系统 ==========\nfunction loadBillingPlans(){\napi('/api/billing/plans').then(function(data){\nvar html=data.map(function(p){\nvar features=JSON.parse(p.features||'[]');\nreturn'<div class=\"price-card\" onclick=\"subscribePlan(\\''+p.id+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">¥'+p.price+'<span>/月</span></div><ul>'+features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn btn-primary\" style=\"width:100%\">选择</button></div>'\n}).join('');\n$('billingPlans').innerHTML=html\n}).catch(function(){})}\n\nfunction loadSubscription(){\napi('/api/billing/subscription').then(function(data){\n$('currentPlanName').textContent=data.plan_name||data.plan||'免费版';\nvar remaining=data.tokens_limit===-1?'无限':formatNumber(data.tokens_limit||10000);\n$('remainingQuota').textContent=remaining\n}).catch(function(){})}\n\nfunction loadUsageStats(){\napi('/api/billing/usage?period=month').then(function(data){\nvar html='';\nfor(var type in data.usage){\nvar u=data.usage[type];\nhtml+='<div style=\"padding:16px;background:var(--bg);border-radius:10px;text-align:center\"><div style=\"font-size:24px;font-weight:600;color:var(--accent)\">'+formatNumber(u.amount)+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+type+'</div><div style=\"font-size:11px;color:var(--success);margin-top:4px\">¥'+u.cost.toFixed(2)+'</div></div>'\n}\n$('usageStats').innerHTML=html||'<p style=\"color:var(--text2);grid-column:1/-1;text-align:center\">暂无用量数据</p>'\n}).catch(function(){})}\n\nfunction loadInvoices(){\napi('/api/billing/invoices').then(function(data){\nif(data.length===0){$('invoiceList').innerHTML='<p style=\"color:var(--text2)\">暂无发票</p>';return}\nvar html=data.map(function(inv){\nvar statusColor=inv.status==='paid'?'var(--success)':'var(--warning)';\nreturn'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div><div style=\"font-weight:500\">'+inv.id+'</div><div style=\"font-size:12px;color:var(--text2)\">'+(inv.created_at||'').slice(0,10)+'</div></div><div style=\"text-align:right\"><div style=\"font-weight:600\">¥'+inv.amount+'</div><div style=\"font-size:12px;color:'+statusColor+'\">'+(inv.status==='paid'?'已支付':'待支付')+'</div></div>'+(inv.status!=='paid'?'<button class=\"btn btn-primary btn-sm\" onclick=\"payInvoice(\\''+inv.id+'\\')\">支付</button>':'')+'</div>'\n}).join('');\n$('invoiceList').innerHTML=html\n}).catch(function(){})}\n\nfunction subscribePlan(planId){\nif(!authToken){alert('请先登录');return}\nif(!confirm('确定订阅此套餐?'))return;\napi('/api/billing/subscribe',{method:'POST',body:JSON.stringify({plan_id:planId,months:1})}).then(function(data){\nshowToast('订阅成功,请支付发票');\nloadInvoices();\nloadSubscription()\n}).catch(function(e){alert('订阅失败: '+e.message)})}\n\nfunction payInvoice(invoiceId){\nif(!confirm('确定支付?'))return;\napi('/api/billing/pay/'+invoiceId,{method:'POST',body:JSON.stringify({method:'alipay'})}).then(function(){\nshowToast('支付成功!');\nloadInvoices();\nloadSubscription()\n}).catch(function(e){alert('支付失败: '+e.message)})}\n\n// ========== RBAC 权限 ==========\nfunction loadMyPermissions(){\napi('/api/rbac/my-permissions').then(function(data){\nvar html=data.permissions.map(function(p){\nreturn'<span class=\"tag tag-primary\">'+p+'</span>'\n}).join('');\n$('myPermissions').innerHTML=html||'<span style=\"color:var(--text2)\">暂无权限</span>'\n}).catch(function(){})}\n\nfunction loadRoles(){\napi('/api/rbac/roles').then(function(data){\nvar html=data.map(function(r){\nvar perms=JSON.parse(r.permissions||'[]');\nreturn'<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong>'+r.name+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.description+'</span></div><div style=\"display:flex;flex-wrap:wrap;gap:6px\">'+perms.map(function(p){return'<span class=\"tag\">'+p+'</span>'}).join('')+'</div></div>'\n}).join('');\n$('rolesList').innerHTML=html\n}).catch(function(){})}\n\nfunction showCreateRoleModal(){\nvar html='<div class=\"form-group\"><label>角色名称</label><input type=\"text\" id=\"newRoleName\" placeholder=\"role_name\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"newRoleDesc\" placeholder=\"角色描述\"></div><div class=\"form-group\"><label>权限(逗号分隔)</label><input type=\"text\" id=\"newRolePerms\" placeholder=\"chat,notes,memory\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createRole()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'roleModal\\')\">取消</button></div>';\nshowCustomModal('创建角色',html,'roleModal')}\n\nfunction createRole(){\nvar name=$('newRoleName').value.trim();\nvar desc=$('newRoleDesc').value.trim();\nvar perms=$('newRolePerms').value.split(',').map(function(p){return p.trim()}).filter(function(p){return p});\nif(!name){alert('请输入角色名称');return}\napi('/api/rbac/roles',{method:'POST',body:JSON.stringify({name:name,description:desc,permissions:perms})}).then(function(){\ncloseModal('roleModal');\nloadRoles();\nshowToast('角色已创建')\n}).catch(function(e){alert('创建失败: '+e.message)})}\n\n// 初始化时加载推荐\nsetTimeout(loadRecommendations,1000);\nsetTimeout(loadIntegrations,100);\n\n// ========== 快捷键帮助 ==========\nfunction showHotkeyHelp(){\nvar html='<div style=\"display:grid;gap:8px\">';\nvar hotkeys=[\n['Ctrl + N','新建对话'],\n['Ctrl + K','全局搜索'],\n['Ctrl + D','切换主题'],\n['Ctrl + H','系统状态'],\n['Ctrl + B','批量选择'],\n['Ctrl + F','搜索当前对话'],\n['Ctrl + /','快捷键帮助'],\n['Enter','发送消息'],\n['Shift + Enter','换行'],\n['Escape','关闭弹窗']\n];\nhotkeys.forEach(function(h){\nhtml+='<div class=\"hotkey-help-item\"><span>'+h[1]+'</span><span class=\"hotkey-help-key\">'+h[0]+'</span></div>'\n});\nhtml+='</div>';\nshowCustomModal('⌨️ 快捷键帮助',html,'hotkeyHelpModal')}\n\n// ========== 欢迎引导 ==========\nfunction showWelcomeGuide(){\nif(localStorage.getItem('welcomeShown'))return;\nvar html='<div style=\"text-align:center;padding:20px\"><div style=\"font-size:48px;margin-bottom:16px\">🤖</div><h2 style=\"margin-bottom:12px\">欢迎使用 AI Hub</h2><p style=\"color:var(--text2);margin-bottom:24px\">一站式 AI 平台,支持多模型、多功能</p><div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:12px;text-align:left;margin-bottom:24px\"><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">💬</span><div style=\"font-weight:500;margin-top:8px\">多模型对话</div><div style=\"font-size:12px;color:var(--text2)\">支持 OpenAI、Claude、Gemini 等</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">🎨</span><div style=\"font-weight:500;margin-top:8px\">图片生成</div><div style=\"font-size:12px;color:var(--text2)\">DALL-E 3 AI 绘图</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">📚</span><div style=\"font-weight:500;margin-top:8px\">知识库</div><div style=\"font-size:12px;color:var(--text2)\">上传文档,智能问答</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">👥</span><div style=\"font-weight:500;margin-top:8px\">团队协作</div><div style=\"font-size:12px;color:var(--text2)\">多人共享对话和资源</div></div></div><button class=\"btn btn-primary\" onclick=\"closeModal(\\'welcomeModal\\');localStorage.setItem(\\'welcomeShown\\',\\'1\\')\">开始使用</button></div>';\nshowCustomModal('',html,'welcomeModal')}\nsetTimeout(showWelcomeGuide,500);\n\nconsole.log('🤖 AI Hub v2.0.0 - Enhanced');\n</script>\n</body>\n</html>\n"}, "679041fcdaeb53b3cfc7913a48c2f5388f89a886": {"t": 1785765457.3512113, "n": 257678, "h": "2b1fc2b410272e23", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"theme-color\" content=\"#0f0f1a\">\n<meta name=\"description\" content=\"AI Hub - 统一 AI 平台\">\n<link rel=\"manifest\" href=\"/static/manifest.json\">\n<link rel=\"apple-touch-icon\" href=\"/static/icon-192.png\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0;overflow-y:auto;overflow-x:hidden}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px;flex:1;overflow-y:auto}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"local-models\"><span class=\"nav-item-icon\">🏠</span> 本地模型</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"traces\"><span class=\"nav-item-icon\">🔍</span> 链路追踪</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n<div class=\"nav-item\" data-page=\"rag\"><span class=\"nav-item-icon\">🔍</span> RAG 检索</div>\n<div class=\"nav-item\" data-page=\"billing\"><span class=\"nav-item-icon\">💳</span> 订阅计费</div>\n<div class=\"nav-item\" data-page=\"rbac\"><span class=\"nav-item-icon\">🛡️</span> 权限管理</div>\n<div class=\"nav-item\" data-page=\"audit\"><span class=\"nav-item-icon\">📜</span> 审计日志</div>\n<div class=\"nav-item\" data-page=\"security\"><span class=\"nav-item-icon\">🔒</span> 安全中心</div>\n<div class=\"nav-item\" data-page=\"monitoring\"><span class=\"nav-item-icon\">📊</span> 系统监控</div>\n<div class=\"nav-item\" data-page=\"tasks\"><span class=\"nav-item-icon\">⚙️</span> 任务队列</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"integrations\"><span class=\"nav-item-icon\">🔗</span> 第三方集成</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"workflows\"><span class=\"nav-item-icon\">🤖</span> Agent 工作流</div>\n<div class=\"nav-item\" data-page=\"code-runner\"><span class=\"nav-item-icon\">▶️</span> 代码运行</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" onclick=\"showHealthDashboard()\"><span class=\"nav-item-icon\">🖥️</span> 系统状态</div>\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\" title=\"批量操作\">☑️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div id=\"batchActions\" style=\"display:none;padding:8px;background:var(--bg3);gap:8px;align-items:center\">\n<span style=\"font-size:12px\">已选 <span id=\"selectedCount\">0</span> 个</span>\n<button class=\"btn btn-danger btn-sm\" onclick=\"batchDeleteChats()\">删除</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"batchExportChats()\">导出</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\">取消</button>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"quickReplies\" style=\"display:none;padding:8px 0;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap\"></div>\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateImage()\" title=\"生成图片\">🎨</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateMindmap()\" title=\"生成思维导图\">🧠</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"saveAsTemplate()\" title=\"保存为模板\">💾</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 本地模型页 -->\n<div id=\"page-local-models\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🏠</span> 本地模型 (Ollama)</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">使用 Ollama 运行本地大语言模型,数据完全私有</p>\n<div style=\"display:flex;gap:12px;margin-bottom:20px\">\n<button class=\"btn btn-primary\" onclick=\"loadOllamaModels()\">🔄 刷新模型</button>\n<button class=\"btn btn-ghost\" onclick=\"showPullModelModal()\">📥 拉取模型</button>\n<a href=\"https://ollama.ai\" target=\"_blank\" class=\"btn btn-ghost\">📖 Ollama 官网</a>\n</div>\n<div id=\"ollamaStatus\" style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:16px\"></div>\n<div id=\"ollamaModelList\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 本地模型对话</h4>\n<div class=\"form-group\"><label>选择模型</label><select id=\"ollamaModelSelect\" style=\"width:100%;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select></div>\n<div class=\"form-group\"><label>消息</label><textarea id=\"ollamaMessage\" rows=\"4\" placeholder=\"输入消息...\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"chatWithOllama()\">发送</button>\n<div id=\"ollamaResponse\" style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:8px;min-height:100px;display:none\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚡</span> vLLM 服务</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">高性能推理服务器</p>\n<div class=\"form-group\"><label>vLLM 地址</label><input type=\"text\" id=\"vllmUrl\" value=\"http://localhost:8080\" placeholder=\"http://localhost:8080\"></div>\n<button class=\"btn btn-ghost\" onclick=\"loadVLLMModels()\">检查连接</button>\n<div id=\"vllmStatus\" style=\"margin-top:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">双因素认证 (2FA)<br><small style=\"color:var(--text2)\">使用 Google Authenticator 等应用增强账户安全</small></div><div style=\"display:flex;gap:8px\"><span id=\"2faStatus\" style=\"color:var(--text2)\">未启用</span><button class=\"btn btn-ghost btn-sm\" onclick=\"setup2FA()\" id=\"2faBtn\">设置</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录设备管理</div><button class=\"btn btn-ghost btn-sm\" onclick=\"alert('功能开发中')\">查看设备</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">修改密码</div><button class=\"btn btn-ghost btn-sm\" onclick=\"showChangePasswordModal()\">修改</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复<br><small style=\"color:var(--text2)\">导出/导入所有数据(对话、笔记、记忆、设置)</small></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-primary\" onclick=\"exportAllData()\">📤 导出全部</button><button class=\"btn btn-ghost\" onclick=\"importAllData()\">📥 导入数据</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据库优化<br><small style=\"color:var(--text2)\">清理过期数据,优化数据库性能</small></div><button class=\"btn btn-ghost\" onclick=\"optimizeDatabase()\">🔧 优化数据库</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n<button class=\"btn btn-primary\" onclick=\"showUsageAnalytics()\">📈 详细分析</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 链路追踪页 -->\n<div id=\"page-traces\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔍</span> 链路追踪</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"loadTraces()\">🔄 刷新</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportTraces()\">📥 导出</button>\n</div>\n</div>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:20px\">监控 API 请求的完整调用链路,分析性能瓶颈</p>\n<div id=\"tracesList\"><p style=\"color:var(--text2)\">点击刷新加载追踪记录</p></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 性能概览</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--accent)\" id=\"traceAvgLatency\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">平均延迟</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--success)\" id=\"traceSuccessRate\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">成功率</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--warning)\" id=\"traceCount\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总追踪数</div>\n</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- RAG 检索页 -->\n<div id=\"page-rag\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> RAG 语义检索</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">基于向量的语义搜索,让 AI 理解你的文档内容</p>\n<div class=\"form-group\"><label>选择知识库</label><select id=\"ragKbSelect\" style=\"width:100%;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select></div>\n<div class=\"form-group\"><label>搜索问题</label><input type=\"text\" id=\"ragQuery\" placeholder=\"输入你的问题...\"></div>\n<button class=\"btn btn-primary\" onclick=\"searchRAG()\">🔍 语义搜索</button>\n<button class=\"btn btn-ghost\" onclick=\"chatWithRAG()\" style=\"margin-left:8px\">💬 RAG 对话</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 搜索结果</h4>\n<div id=\"ragResults\" style=\"min-height:100px\"><p style=\"color:var(--text2)\">输入问题后点击搜索</p></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📤</span> 索引文档</h4>\n<div class=\"form-group\"><label>文档内容</label><textarea id=\"ragContent\" rows=\"6\" placeholder=\"粘贴文档内容...\"></textarea></div>\n<div class=\"form-group\"><label>文件名</label><input type=\"text\" id=\"ragFilename\" placeholder=\"document.txt\"></div>\n<button class=\"btn btn-primary\" onclick=\"indexDocument()\">📥 索引文档</button>\n</div>\n</div></div></div></div>\n<!-- 订阅计费页 -->\n<div id=\"page-billing\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💳</span> 订阅计费</h4>\n<div id=\"currentSubscription\" style=\"padding:20px;background:var(--bg);border-radius:12px;margin-bottom:20px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div><div style=\"font-size:12px;color:var(--text2)\">当前套餐</div><div style=\"font-size:24px;font-weight:600\" id=\"currentPlanName\">免费版</div></div>\n<div style=\"text-align:right\"><div style=\"font-size:12px;color:var(--text2)\">剩余额度</div><div style=\"font-size:24px;font-weight:600;color:var(--accent)\" id=\"remainingQuota\">10,000</div></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 套餐选择</h4>\n<div id=\"billingPlans\" class=\"price-cards\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 用量统计</h4>\n<div id=\"usageStats\" style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🧾</span> 发票记录</h4>\n<div id=\"invoiceList\"></div>\n</div>\n</div></div></div></div>\n<!-- 权限管理页 -->\n<div id=\"page-rbac\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🛡️</span> 权限管理</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">基于角色的访问控制 (RBAC)</p>\n<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<div style=\"font-size:12px;color:var(--text2);margin-bottom:8px\">我的权限</div>\n<div id=\"myPermissions\" style=\"display:flex;flex-wrap:wrap;gap:8px\"></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👥</span> 角色列表</h4>\n<div id=\"rolesList\"></div>\n<button class=\"btn btn-ghost\" onclick=\"showCreateRoleModal()\" style=\"margin-top:12px\">+ 创建角色</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> 权限说明</h4>\n<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:12px;font-size:13px\">\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>chat</strong> - 对话功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>notes</strong> - 笔记功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>memory</strong> - 全局记忆</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>image</strong> - 图片生成</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>code</strong> - 代码运行</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>rag</strong> - RAG 检索</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>admin</strong> - 管理功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>*</strong> - 所有权限</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 审计日志页 -->\n<div id=\"page-audit\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📜</span> 审计日志</h4>\n<div style=\"display:flex;gap:8px\">\n<select id=\"auditEventFilter\" style=\"padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\" onchange=\"loadAuditLogs()\">\n<option value=\"\">全部事件</option>\n<option value=\"user.login\">用户登录</option>\n<option value=\"data.export\">数据导出</option>\n<option value=\"settings.change\">设置变更</option>\n<option value=\"payment.create\">支付创建</option>\n<option value=\"security.alert\">安全警报</option>\n</select>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"loadAuditLogs()\">🔄 刷新</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportAuditLogs()\">📥 导出</button>\n</div>\n</div>\n<div id=\"auditLogsList\" style=\"max-height:400px;overflow-y:auto\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 合规报告</h4>\n<div style=\"display:flex;gap:12px;margin-bottom:16px\">\n<button class=\"btn btn-primary\" onclick=\"generateComplianceReport('month')\">月度报告</button>\n<button class=\"btn btn-ghost\" onclick=\"generateComplianceReport('quarter')\">季度报告</button>\n<button class=\"btn btn-ghost\" onclick=\"generateComplianceReport('year')\">年度报告</button>\n</div>\n<div id=\"complianceReport\"></div>\n</div>\n</div></div></div></div>\n<!-- 安全中心页 -->\n<div id=\"page-security\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔒</span> 安全中心</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:20px\">\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"blockedIpsCount\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">封禁 IP</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"failedAttemptsCount\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">失败尝试</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"twoFaUsersCount\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">2FA 用户</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"securityScore\">A</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">安全评分</div>\n</div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"loadSecurityStatus()\">🔄 刷新状态</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> IP 封禁管理</h4>\n<div class=\"form-group\"><label>解封 IP</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"unblockIpInput\" placeholder=\"192.168.1.1\"><button class=\"btn btn-ghost\" onclick=\"unblockIP()\">解封</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">强制密码复杂度<br><small style=\"color:var(--text2)\">要求密码包含大小写、数字和特殊字符</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录失败锁定<br><small style=\"color:var(--text2)\">5次失败后锁定1小时</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">会话超时<br><small style=\"color:var(--text2)\">30天无活动自动登出</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 系统监控页 -->\n<div id=\"page-monitoring\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 系统监控</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:20px\">\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"cpuUsage\">0%</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">CPU 使用率</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"memoryUsage\">0%</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">内存使用率</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"diskUsage\">0%</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">磁盘使用率</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--text)\" id=\"uptimeDisplay\">0h</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">运行时间</div>\n</div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"loadSystemMetrics()\">🔄 刷新指标</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 性能指标</h4>\n<div id=\"performanceMetrics\" style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 告警列表</h4>\n<div id=\"alertsList\" style=\"max-height:300px;overflow-y:auto\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> 链路追踪</h4>\n<div id=\"tracesList\" style=\"max-height:300px;overflow-y:auto\"></div>\n</div>\n</div></div></div></div>\n<!-- 任务队列页 -->\n<div id=\"page-tasks\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 任务队列</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:20px\">\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"pendingTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">待处理</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"runningTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">运行中</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"completedTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">已完成</div>\n</div>\n<div style=\"padding:20px;background:var(--bg);border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"failedTasks\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">失败</div>\n</div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"loadTaskQueue()\">🔄 刷新队列</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 任务列表</h4>\n<div id=\"tasksList\" style=\"max-height:400px;overflow-y:auto\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⏰</span> 定时任务</h4>\n<div id=\"scheduledJobs\" style=\"max-height:300px;overflow-y:auto\"></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- 第三方集成页 -->\n<div id=\"page-integrations\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔗</span> 第三方集成</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:20px\">连接 Slack、飞书等平台,让 AI 助手无处不在</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> Slack 集成</h4>\n<div class=\"form-group\"><label>Bot Token</label><input type=\"password\" id=\"slackToken\" placeholder=\"xoxb-...\" onchange=\"saveIntegration('slack')\"></div>\n<div class=\"form-group\"><label>Signing Secret</label><input type=\"password\" id=\"slackSecret\" placeholder=\"签名密钥\" onchange=\"saveIntegration('slack')\"></div>\n<div class=\"form-group\"><label>Webhook URL</label><div style=\"display:flex;gap:8px\"><input type=\"text\" value=\"http://localhost:8000/api/integrations/slack/webhook\" readonly style=\"flex:1;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText(this.previousElementSibling.value)\">📋</button></div></div>\n<div style=\"display:flex;gap:12px;margin-top:16px\">\n<button class=\"btn btn-primary\" onclick=\"testSlackIntegration()\">🧪 测试连接</button>\n<button class=\"btn btn-ghost\" onclick=\"window.open('https://api.slack.com/apps','_blank')\">📖 创建 Slack App</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐦</span> 飞书集成</h4>\n<div class=\"form-group\"><label>App ID</label><input type=\"text\" id=\"feishuAppId\" placeholder=\"cli_...\" onchange=\"saveIntegration('feishu')\"></div>\n<div class=\"form-group\"><label>App Secret</label><input type=\"password\" id=\"feishuSecret\" placeholder=\"应用密钥\" onchange=\"saveIntegration('feishu')\"></div>\n<div class=\"form-group\"><label>Webhook URL</label><div style=\"display:flex;gap:8px\"><input type=\"text\" value=\"http://localhost:8000/api/integrations/feishu/webhook\" readonly style=\"flex:1;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText(this.previousElementSibling.value)\">📋</button></div></div>\n<div style=\"display:flex;gap:12px;margin-top:16px\">\n<button class=\"btn btn-primary\" onclick=\"testFeishuIntegration()\">🧪 测试连接</button>\n<button class=\"btn btn-ghost\" onclick=\"window.open('https://open.feishu.cn/app','_blank')\">📖 创建飞书应用</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> Webhook 通知</h4>\n<div class=\"form-group\"><label>通知 URL</label><input type=\"text\" id=\"webhookUrl\" placeholder=\"https://your-server.com/webhook\" onchange=\"saveIntegration('webhook')\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">新消息通知</div><label class=\"switch\"><input type=\"checkbox\" id=\"webhookNewMsg\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">错误通知</div><label class=\"switch\"><input type=\"checkbox\" id=\"webhookError\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🎛️</span> 灰度发布</h4>\n<div id=\"featureFlagsList\"></div>\n<button class=\"btn btn-ghost\" onclick=\"loadFeatureFlags()\" style=\"margin-top:12px\">🔄 刷新</button>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Agent 工作流页 -->\n<div id=\"page-workflows\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🤖</span> Agent 工作流</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建多步骤自动化任务,让 AI 按流程完成复杂工作</p>\n<div id=\"workflowTemplates\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👥</span> 多 Agent 协作</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">多个 AI Agent 协同完成复杂任务</p>\n<div class=\"form-group\"><label>任务描述</label><textarea id=\"multiAgentTask\" rows=\"3\" placeholder=\"描述你需要完成的任务...\"></textarea></div>\n<div class=\"form-group\"><label>选择 Agent</label>\n<div id=\"agentCheckboxes\" style=\"display:flex;flex-wrap:wrap;gap:12px\"></div>\n</div>\n<div class=\"form-group\"><label>协作模式</label>\n<select id=\"agentMode\" style=\"width:200px;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\">\n<option value=\"sequential\">顺序执行</option>\n<option value=\"parallel\">并行执行</option>\n<option value=\"debate\">辩论模式</option>\n</select>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runMultiAgent()\">🚀 开始协作</button>\n<button class=\"btn btn-ghost\" onclick=\"showCreateAgentModal()\" style=\"margin-left:8px\">+ 创建 Agent</button>\n</div>\n<div class=\"settings-section\" id=\"multiAgentResults\" style=\"display:none\">\n<h4><span>📋</span> 协作结果</h4>\n<div id=\"multiAgentResultsContent\"></div>\n</div>\n<div class=\"settings-section\" id=\"workflowRunner\" style=\"display:none\">\n<h4><span>▶️</span> 运行工作流</h4>\n<div id=\"workflowInputs\"></div>\n<button class=\"btn btn-primary\" onclick=\"executeWorkflow()\">🚀 执行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('workflowRunner').style.display='none'\">取消</button>\n</div>\n<div class=\"settings-section\" id=\"workflowResults\" style=\"display:none\">\n<h4><span>📋</span> 执行结果</h4>\n<div id=\"workflowResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 代码运行器页 -->\n<div id=\"page-code-runner\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>▶️</span> 代码运行器</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">在线运行 Python / JavaScript 代码</p>\n<div class=\"form-group\">\n<label>语言</label>\n<select id=\"codeLanguage\" style=\"width:150px\">\n<option value=\"python\">Python</option>\n<option value=\"javascript\">JavaScript</option>\n</select>\n</div>\n<div class=\"form-group\">\n<label>代码</label>\n<textarea id=\"codeInput\" rows=\"12\" style=\"font-family:monospace;font-size:13px\" placeholder=\"# 输入代码...\nprint('Hello, World!')\"></textarea>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-primary\" onclick=\"runCode()\">▶️ 运行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('codeInput').value=''\">清空</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 输出结果</h4>\n<pre id=\"codeOutput\" style=\"background:var(--bg);padding:16px;border-radius:8px;min-height:100px;font-family:monospace;font-size:13px;white-space:pre-wrap\">等待运行...</pre>\n</div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>系统状态</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + H</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量选择模式</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + B</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量导出</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>搜索当前对话</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + F</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换主题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + D</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><div class=\"form-group\" id=\"auth2FAGroup\" style=\"display:none\"><label>2FA 验证码</label><input type=\"text\" id=\"auth2FACode\" placeholder=\"6位验证码\" maxlength=\"6\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><div style=\"display:flex;align-items:center;margin:16px 0\"><div style=\"flex:1;height:1px;background:var(--border)\"></div><span style=\"padding:0 12px;color:var(--text2);font-size:12px\">或</span><div style=\"flex:1;height:1px;background:var(--border)\"></div></div><button class=\"btn btn-ghost\" style=\"width:100%;display:flex;align-items:center;justify-content:center;gap:8px\" onclick=\"loginWithGithub()\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg> 使用 GitHub 登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();if(n.dataset.page==='workflows')loadWorkflowTemplates();if(n.dataset.page==='traces')loadTraces();if(n.dataset.page==='integrations')loadFeatureFlags();if(n.dataset.page==='rag')loadRAGKnowledgeBases();if(n.dataset.page==='billing'){loadBillingPlans();loadSubscription();loadUsageStats();loadInvoices()}if(n.dataset.page==='rbac'){loadMyPermissions();loadRoles()}if(n.dataset.page==='local-models')loadOllamaModels();if(n.dataset.page==='workflows')loadAgents();if(n.dataset.page==='audit')loadAuditLogs();if(n.dataset.page==='security')loadSecurityStatus();if(n.dataset.page==='monitoring'){loadSystemMetrics();loadAlerts();loadTraces()}if(n.dataset.page==='tasks')loadTaskQueue();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{\n// 先显示置顶的对话\nvar pinnedChats=chats.filter(function(c){return c.pinned});\nvar normalChats=chats.filter(function(c){return !c.pinned&&!c.archived});\nif(pinnedChats.length>0){html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2)\">📌 置顶</div>';pinnedChats.forEach(function(c){html+=renderChatItem(c)})}\nif(normalChats.length>0){if(pinnedChats.length>0)html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2);margin-top:8px\">💬 对话</div>';normalChats.forEach(function(c){html+=renderChatItem(c)})}}$('chatList').innerHTML=html}\nfunction renderChatItem(c){var selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';var checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';var pinIcon=c.pinned?'📌':'💬';return'<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" style=\"'+selected+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">'+pinIcon+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"favoriteMessageByIndex('+i+')\" title=\"收藏\">❤️</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll();showQuickReplies()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var chat=chats.find(function(c){return c.id===id});var pinText=chat&&chat.pinned?'📌 取消置顶':'📌 置顶';var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"togglePinChat(\\''+id+'\\')\">'+pinText+'</div><div onclick=\"archiveChat(\\''+id+'\\')\">📦 归档</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction togglePinChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.pinned=!chat.pinned;saveChats();renderChats();showToast(chat.pinned?'已置顶':'已取消置顶');if(authToken){api('/api/conversations/'+id+'/pin',{method:'POST'}).catch(function(){})}}\nfunction archiveChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.archived=true;chats=chats.filter(function(c){return c.id!==id});saveChats();renderChats();showToast('已归档');if(authToken){api('/api/conversations/'+id+'/archive',{method:'POST'}).catch(function(){})}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Agent 工作流\nvar workflowTemplates=[];\nvar currentWorkflow=null;\nfunction loadWorkflowTemplates(){api('/api/workflows/templates').then(function(data){workflowTemplates=data;renderWorkflowTemplates()}).catch(function(e){console.error('加载工作流失败:',e)})}\nfunction renderWorkflowTemplates(){var html=workflowTemplates.map(function(w){return'<div style=\"background:var(--bg);border-radius:12px;padding:20px;cursor:pointer\" onclick=\"selectWorkflow(\\''+w.id+'\\')\"><div style=\"display:flex;align-items:center;gap:12px;margin-bottom:12px\"><span style=\"font-size:24px\">🤖</span><div><strong>'+w.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+w.steps.length+' 个步骤</div></div></div><p style=\"font-size:13px;color:var(--text2);line-height:1.5\">'+w.description+'</p></div>'}).join('');$('workflowTemplates').innerHTML=html||'<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无工作流模板</div>'}\nfunction selectWorkflow(id){currentWorkflow=workflowTemplates.find(function(w){return w.id===id});if(!currentWorkflow)return;var inputs=[];currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')&&inputs.indexOf(key)===-1)inputs.push(key)})}});var html=inputs.map(function(key){return'<div class=\"form-group\"><label>'+key+'</label><textarea id=\"wf_'+key+'\" rows=\"3\" placeholder=\"输入 '+key+'\"></textarea></div>'}).join('');$('workflowInputs').innerHTML='<h5 style=\"margin-bottom:16px\">'+currentWorkflow.name+'</h5>'+html;$('workflowRunner').style.display='block';$('workflowResults').style.display='none'}\nfunction executeWorkflow(){if(!currentWorkflow){alert('请先选择工作流');return}var inputData={};currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')){var el=$('wf_'+key);if(el)inputData[key]=el.value}})}});$('workflowResultsContent').innerHTML='<div style=\"text-align:center;padding:40px\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px;color:var(--text2)\">正在执行工作流...</p></div>';$('workflowResults').style.display='block';api('/api/workflows/run',{method:'POST',body:JSON.stringify({name:currentWorkflow.name,steps:currentWorkflow.steps,input_data:inputData})}).then(function(data){var html='';for(var key in data.results){html+='<div style=\"background:var(--bg);border-radius:10px;padding:16px;margin-bottom:12px\"><div style=\"font-weight:600;margin-bottom:8px;color:var(--accent)\">'+key+'</div><div style=\"font-size:14px;line-height:1.6;white-space:pre-wrap\">'+data.results[key]+'</div></div>'}$('workflowResultsContent').innerHTML=html}).catch(function(e){$('workflowResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">执行失败: '+e.message+'</div>'})}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// GitHub 登录\nfunction loginWithGithub(){window.location.href='/api/auth/github'}\n// 2FA 设置\nfunction setup2FA(){if(!authToken){alert('请先登录');return}api('/api/auth/2fa/setup',{method:'POST'}).then(function(data){var html='<div style=\"text-align:center\"><img src=\"'+data.qr_code+'\" style=\"width:200px;height:200px;border-radius:8px\"><p style=\"margin:16px 0;color:var(--text2);font-size:13px\">使用 Google Authenticator 扫描二维码</p><div class=\"form-group\"><label>输入6位验证码确认</label><input type=\"text\" id=\"verify2FACode\" placeholder=\"000000\" maxlength=\"6\" style=\"text-align:center;font-size:20px;letter-spacing:8px\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"verify2FA()\">确认启用</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'2faModal\\')\">取消</button></div></div>';showCustomModal('设置双因素认证',html,'2faModal')}).catch(function(e){alert('设置失败: '+e.message)})}\nfunction verify2FA(){var code=$('verify2FACode').value.trim();if(code.length!==6){alert('请输入6位验证码');return}api('/api/auth/2fa/verify',{method:'POST',body:JSON.stringify({code:code})}).then(function(data){closeModal('2faModal');$('2faStatus').textContent='已启用';$('2faStatus').style.color='var(--success)';$('2faBtn').textContent='禁用';$('2faBtn').onclick=disable2FA;showToast('2FA 已启用')}).catch(function(e){alert('验证失败: '+e.message)})}\nfunction disable2FA(){var code=prompt('输入6位验证码以禁用 2FA:');if(!code)return;api('/api/auth/2fa/disable',{method:'POST',body:JSON.stringify({code:code})}).then(function(){$('2faStatus').textContent='未启用';$('2faStatus').style.color='var(--text2)';$('2faBtn').textContent='设置';$('2faBtn').onclick=setup2FA;showToast('2FA 已禁用')}).catch(function(e){alert('禁用失败: '+e.message)})}\nfunction showChangePasswordModal(){var html='<div class=\"form-group\"><label>当前密码</label><input type=\"password\" id=\"oldPassword\"></div><div class=\"form-group\"><label>新密码</label><input type=\"password\" id=\"newPassword\"></div><div class=\"form-group\"><label>确认新密码</label><input type=\"password\" id=\"confirmPassword\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"changePassword()\">修改</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pwdModal\\')\">取消</button></div>';showCustomModal('修改密码',html,'pwdModal')}\nfunction changePassword(){var oldPwd=$('oldPassword').value,newPwd=$('newPassword').value,confirmPwd=$('confirmPassword').value;if(!oldPwd||!newPwd){alert('请填写密码');return}if(newPwd!==confirmPwd){alert('两次密码不一致');return}alert('密码修改功能开发中')}\n// 检查 URL 中的 token(OAuth 回调)\n(function(){var params=new URLSearchParams(window.location.search);var token=params.get('token');if(token){localStorage.setItem('token',token);authToken=token;window.history.replaceState({},document.title,'/');checkAuth()}})();\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\n// 代码运行器\nfunction runCode(){var code=$('codeInput').value;var lang=$('codeLanguage').value;if(!code.trim()){alert('请输入代码');return}$('codeOutput').textContent='运行中...';$('codeOutput').style.color='var(--text2)';api('/api/code/run',{method:'POST',body:JSON.stringify({code:code,language:lang,timeout:5})}).then(function(data){if(data.success){$('codeOutput').textContent=data.output||'(无输出)';$('codeOutput').style.color='var(--success)'}else{$('codeOutput').textContent='错误: '+(data.error||'未知错误')+'\\n'+data.output;$('codeOutput').style.color='var(--error)'}}).catch(function(e){$('codeOutput').textContent='请求失败: '+e.message;$('codeOutput').style.color='var(--error)'})}\n// 思维导图\nfunction generateMindmap(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}showToast('正在生成思维导图...');api('/api/mindmap/generate',{method:'POST',body:JSON.stringify({messages:chat.messages,title:chat.title})}).then(function(data){renderMindmap(data.nodes)}).catch(function(e){alert('生成失败: '+e.message)})}\nfunction renderMindmap(nodes){var html='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.8);z-index:2000;display:flex;align-items:center;justify-content:center\" onclick=\"if(event.target===this)this.remove()\"><div style=\"background:var(--bg2);border-radius:16px;padding:24px;max-width:800px;max-height:80vh;overflow:auto\"><h3 style=\"margin-bottom:16px\">🧠 思维导图</h3><div id=\"mindmapContent\" style=\"padding:20px\"></div><button class=\"btn btn-ghost\" onclick=\"this.parentElement.parentElement.remove()\">关闭</button></div></div>';document.body.insertAdjacentHTML('beforeend',html);var content='';function renderNode(node,level){var indent=level*24;content+='<div style=\"margin-left:'+indent+'px;padding:8px 12px;margin-bottom:4px;background:var(--bg'+(level>0?'3':'')+');border-radius:6px;border-left:3px solid var(--accent)\">'+(level>0?'├─ ':'')+node.label+'</div>';if(node.children){node.children.forEach(function(c){renderNode(c,level+1)})}}if(nodes&&nodes.length)renderNode(nodes[0],0);$('mindmapContent').innerHTML=content||'<p style=\"color:var(--text2)\">无法生成思维导图</p>'}\n// 保存对话为模板\nfunction saveAsTemplate(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}var name=prompt('模板名称:',chat.title);if(!name)return;api('/api/chat-templates',{method:'POST',body:JSON.stringify({name:name,messages:chat.messages})}).then(function(){showToast('已保存为模板')}).catch(function(e){alert('保存失败: '+e.message)})}\n// 用量配额\nfunction loadQuota(){api('/api/quota').then(function(data){var html='<div style=\"margin-bottom:16px\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Token 使用量</span><span>'+formatNumber(data.tokens_used)+' / '+formatNumber(data.tokens_limit)+'</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;overflow:hidden\"><div style=\"background:var(--accent);height:100%;width:'+data.usage_percent+'%\"></div></div></div><p style=\"font-size:12px;color:var(--text2)\">当前套餐: '+data.plan+'</p>';if($('quotaInfo'))$('quotaInfo').innerHTML=html}).catch(function(e){console.error(e)})}\n// PWA 注册\nif('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js').then(function(reg){console.log('SW registered');if('Notification' in window&&Notification.permission==='default'){Notification.requestPermission()}}).catch(function(e){console.error('SW failed:',e)})}\n// 图片生成\nfunction generateImage(){var prompt=prompt('输入图片描述:');if(!prompt)return;showToast('正在生成图片...');api('/api/images/generate',{method:'POST',body:JSON.stringify({prompt:prompt})}).then(function(data){var img='<img src=\"'+data.url+'\" style=\"max-width:100%;border-radius:8px\">';var chat=chats.find(function(c){return c.id===currentChatId});if(chat){chat.messages.push({role:'assistant',content:'![生成的图片]('+data.url+')\\n\\n'+data.revised_prompt});saveChats();renderMessages()}showToast('图片已生成')}).catch(function(e){alert('生成失败: '+e.message)})}\n// TTS 语音合成\nfunction speakText(text){api('/api/audio/tts',{method:'POST',body:JSON.stringify({text:text,voice:'alloy'})}).then(function(data){var audio=new Audio(data.audio);audio.play();showToast('正在播放')}).catch(function(e){if('speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(text);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('TTS 失败: '+e.message)}})}\n// 内容过滤\nfunction filterContent(text){return api('/api/content/filter',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data})}\n// 数据脱敏\nfunction maskData(text){return api('/api/data/mask',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data.masked})}\n// 备份\nfunction createBackup(){api('/api/backup',{method:'POST'}).then(function(data){showToast('备份已创建: '+data.path)}).catch(function(e){alert('备份失败: '+e.message)})}\n// 离线检测\nwindow.addEventListener('online',function(){showToast('网络已恢复')});\nwindow.addEventListener('offline',function(){showToast('网络已断开,部分功能不可用')});\n\n// ========== 性能监控面板 ==========\nfunction showHealthDashboard(){\napi('/api/health/detailed').then(function(data){\nvar html='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">CPU 使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.cpu_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.cpu_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">内存使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.memory_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.memory_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">磁盘使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.disk_percent>90?'var(--error)':'var(--success)')+'\">'+data.system.disk_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">数据库延迟</div><div style=\"font-size:24px;font-weight:600;color:'+(data.components.database.latency_ms>100?'var(--warning)':'var(--success)')+'\">'+data.components.database.latency_ms+'ms</div></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:10px\">';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>缓存</span><span>'+data.components.cache.size+'/'+data.components.cache.max_size+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Redis</span><span style=\"color:'+(data.components.redis.status==='healthy'?'var(--success)':'var(--warning)')+'\">'+data.components.redis.status+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between\"><span>待处理任务</span><span>'+data.components.task_queue.pending_tasks+'</span></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;text-align:center;font-size:12px;color:var(--text2)\">版本 '+data.version+' · 运行时间 '+formatUptime(data.uptime_seconds)+'</div>';\nshowCustomModal('🖥️ 系统状态',html,'healthModal')\n}).catch(function(e){alert('获取状态失败: '+e.message)})}\nfunction formatUptime(seconds){var h=Math.floor(seconds/3600);var m=Math.floor((seconds%3600)/60);return h+'小时'+m+'分钟'}\n\n// ========== 批量操作 ==========\nvar batchMode=false;\nvar selectedChats=[];\nfunction toggleBatchMode(){batchMode=!batchMode;selectedChats=[];if(batchMode){$('batchActions').style.display='flex';showToast('已进入批量选择模式')}else{$('batchActions').style.display='none'}renderChatList()}\nfunction toggleChatSelection(id,e){if(!batchMode)return;e.stopPropagation();var idx=selectedChats.indexOf(id);if(idx>=0){selectedChats.splice(idx,1)}else{selectedChats.push(id)}renderChatList();$('selectedCount').textContent=selectedChats.length}\nfunction batchDeleteChats(){if(selectedChats.length===0){alert('请先选择对话');return}if(!confirm('确定删除 '+selectedChats.length+' 个对话?'))return;api('/api/conversations/batch-delete',{method:'POST',body:JSON.stringify({ids:selectedChats})}).then(function(data){showToast('已删除 '+data.deleted+' 个对话');selectedChats=[];batchMode=false;$('batchActions').style.display='none';loadChats()}).catch(function(e){alert('删除失败: '+e.message)})}\nfunction batchExportChats(){if(selectedChats.length===0){alert('请先选择对话');return}api('/api/messages/batch-export',{method:'POST',body:JSON.stringify({conversation_ids:selectedChats,format:'json'})}).then(function(data){var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='conversations_export.json';a.click();showToast('已导出 '+data.count+' 个对话')}).catch(function(e){alert('导出失败: '+e.message)})}\n\n// ========== 数据库优化 ==========\nfunction optimizeDatabase(){if(!confirm('确定要优化数据库?这将清理过期数据。'))return;showToast('正在优化...');api('/api/admin/optimize-db',{method:'POST'}).then(function(data){showToast(data.message)}).catch(function(e){alert('优化失败: '+e.message)})}\n\n// ========== 快捷键增强 ==========\ndocument.addEventListener('keydown',function(e){\nif(e.ctrlKey&&e.key==='h'){e.preventDefault();showHealthDashboard()}\nif(e.ctrlKey&&e.key==='b'){e.preventDefault();toggleBatchMode()}\nif(e.ctrlKey&&e.shiftKey&&e.key==='E'){e.preventDefault();batchExportChats()}\nif(e.ctrlKey&&e.key==='f'){e.preventDefault();searchInCurrentChat()}\nif(e.ctrlKey&&e.key==='/'||e.key==='?'){e.preventDefault();showHotkeyHelp()}\n});\n\n// ========== 性能优化:虚拟滚动 ==========\nfunction renderChatListVirtual(){\nvar container=$('chatList');\nvar itemHeight=60;\nvar visibleCount=Math.ceil(container.clientHeight/itemHeight)+2;\nvar scrollTop=container.scrollTop;\nvar startIndex=Math.floor(scrollTop/itemHeight);\nvar endIndex=Math.min(startIndex+visibleCount,chats.length);\nvar html='<div style=\"height:'+(startIndex*itemHeight)+'px\"></div>';\nfor(var i=startIndex;i<endIndex;i++){\nvar c=chats[i];\nvar active=c.id===currentChatId?'active':'';\nvar selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';\nvar checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';\nhtml+='<div class=\"sidebar-item '+active+'\" style=\"'+selected+'\" onclick=\"loadChat(\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+c.title+'</div><div class=\"sidebar-item-desc\">'+(c.messages.length||0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" style=\"opacity:0\" onclick=\"deleteChat(\\''+c.id+'\\',event)\">🗑️</button></div>'\n}\nhtml+='<div style=\"height:'+((chats.length-endIndex)*itemHeight)+'px\"></div>';\ncontainer.innerHTML=html}\n\n// ========== 请求重试机制 ==========\nasync function apiWithRetry(url,options,maxRetries=3){\nfor(var i=0;i<maxRetries;i++){\ntry{return await api(url,options)}\ncatch(e){\nif(i===maxRetries-1)throw e;\nawait new Promise(function(r){setTimeout(r,1000*(i+1))});\nconsole.log('Retrying request...',i+1)\n}}}\n\n// ========== 消息队列(离线支持) ==========\nvar offlineQueue=JSON.parse(localStorage.getItem('offlineQueue')||'[]');\nfunction queueOfflineMessage(msg){offlineQueue.push({msg:msg,time:Date.now()});localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))}\nfunction processOfflineQueue(){if(offlineQueue.length===0)return;showToast('正在发送离线消息...');var msg=offlineQueue.shift();localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue));sendMessageInternal(msg.msg).then(function(){processOfflineQueue()}).catch(function(){offlineQueue.unshift(msg);localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))})}\nwindow.addEventListener('online',processOfflineQueue);\n\n// ========== 智能预加载 ==========\nfunction preloadNextChat(){\nvar currentIdx=chats.findIndex(function(c){return c.id===currentChatId});\nif(currentIdx>=0&&currentIdx<chats.length-1){\nvar nextChat=chats[currentIdx+1];\nif(!nextChat.messages||nextChat.messages.length===0){\napi('/api/conversations/'+nextChat.id+'/messages').then(function(msgs){nextChat.messages=msgs})}}}\n\n// ========== 自动保存草稿 ==========\nvar draftTimer=null;\nfunction saveDraft(){var input=$('chatInput').value;if(input&&currentChatId){localStorage.setItem('draft_'+currentChatId,input)}}\nfunction loadDraft(){if(currentChatId){var draft=localStorage.getItem('draft_'+currentChatId);if(draft)$('chatInput').value=draft}}\nfunction clearDraft(){if(currentChatId)localStorage.removeItem('draft_'+currentChatId)}\n$('chatInput').addEventListener('input',function(){clearTimeout(draftTimer);draftTimer=setTimeout(saveDraft,1000)});\n\n// ========== 消息搜索增强 ==========\nfunction searchInCurrentChat(){var q=prompt('在当前对话中搜索:');if(!q)return;var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages)return;var results=chat.messages.filter(function(m){return m.content&&m.content.toLowerCase().includes(q.toLowerCase())});if(results.length===0){alert('未找到匹配消息');return}var html='<div style=\"max-height:400px;overflow-y:auto\">';results.forEach(function(m,i){html+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:4px\">'+(m.role==='user'?'👤 用户':'🤖 助手')+'</div><div style=\"font-size:14px\">'+m.content.slice(0,200)+(m.content.length>200?'...':'')+'</div></div>'});html+='</div>';showCustomModal('搜索结果 ('+results.length+')',html,'searchResultModal')}\n\n// ========== 快速回复 ==========\nvar quickReplies=[\n{id:'continue',text:'继续',prompt:'请继续'},\n{id:'explain',text:'解释',prompt:'请详细解释一下'},\n{id:'example',text:'举例',prompt:'请举个例子'},\n{id:'simplify',text:'简化',prompt:'请用更简单的语言解释'},\n{id:'code',text:'代码',prompt:'请给出代码示例'},\n{id:'summary',text:'总结',prompt:'请总结一下要点'}\n];\nfunction showQuickReplies(){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages||chat.messages.length===0){$('quickReplies').style.display='none';return}\nvar lastMsg=chat.messages[chat.messages.length-1];\nif(lastMsg.role!=='assistant'){$('quickReplies').style.display='none';return}\nvar html=quickReplies.map(function(r){return'<button class=\"btn btn-ghost btn-sm\" onclick=\"sendQuickReply(\\''+r.prompt+'\\')\">'+r.text+'</button>'}).join('');\n$('quickReplies').innerHTML=html;\n$('quickReplies').style.display='flex'}\nfunction sendQuickReply(prompt){$('chatInput').value=prompt;sendMessage()}\n\n// ========== 数据导入导出 ==========\nfunction exportAllData(){\nif(!authToken){alert('请先登录');return}\nshowToast('正在导出数据...');\napi('/api/data/export-all',{method:'POST'}).then(function(data){\nvar blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='ai_hub_backup_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})}\n\nfunction importAllData(){\nif(!authToken){alert('请先登录');return}\nvar input=document.createElement('input');\ninput.type='file';\ninput.accept='.json';\ninput.onchange=function(e){\nvar file=e.target.files[0];\nif(!file)return;\nvar reader=new FileReader();\nreader.onload=function(ev){\ntry{\nvar data=JSON.parse(ev.target.result);\nif(!confirm('确定要导入数据?这将添加 '+\n(data.conversations?data.conversations.length:0)+' 个对话、'+\n(data.notes?data.notes.length:0)+' 个笔记'))return;\napi('/api/data/import',{method:'POST',body:JSON.stringify(data)}).then(function(result){\nshowToast('导入完成: '+result.imported.conversations+' 对话, '+result.imported.notes+' 笔记');\nloadChats()\n}).catch(function(e){alert('导入失败: '+e.message)})\n}catch(e){alert('文件格式错误')}};\nreader.readAsText(file)};\ninput.click()}\n\n// ========== 智能推荐 ==========\nfunction loadRecommendations(){\napi('/api/recommendations').then(function(data){\nif(data.features&&data.features.length>0){\nvar html='<div style=\"padding:16px;background:var(--bg3);border-radius:10px;margin-bottom:16px\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:12px\">💡 推荐功能</div><div style=\"display:flex;gap:12px;flex-wrap:wrap\">';\ndata.features.forEach(function(f){\nhtml+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;cursor:pointer;flex:1;min-width:150px\" onclick=\"showFeatureGuide(\\''+f.name+'\\')\"><span style=\"font-size:20px\">'+f.icon+'</span><div style=\"font-size:14px;font-weight:500;margin-top:8px\">'+f.name+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+f.desc+'</div></div>'});\nhtml+='</div></div>';\nvar container=$('chatMessages');\nif(container&&container.querySelector('.empty-state')){\ncontainer.innerHTML=html+container.innerHTML}}\n}).catch(function(){})}\nfunction showFeatureGuide(name){\nvar guides={\n'知识库':'点击左侧导航的\"知识库\",创建知识库并上传文档,AI 将基于您的资料回答问题。',\n'团队协作':'点击左侧导航的\"团队空间\",创建团队并邀请成员,共享对话和资源。'\n};\nalert(guides[name]||'功能介绍开发中')}\n\n// ========== 收藏消息 ==========\nfunction favoriteMessage(content){\nif(!authToken){alert('请先登录');return}\napi('/api/messages/favorite',{method:'POST',body:JSON.stringify({\nconversation_id:currentChatId,\ncontent:content\n})}).then(function(){showToast('已收藏到记忆')}).catch(function(e){alert('收藏失败: '+e.message)})}\nfunction favoriteMessageByIndex(index){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages[index])return;\nfavoriteMessage(chat.messages[index].content)}\n\n// ========== 使用分析 ==========\nfunction showUsageAnalytics(){\napi('/api/analytics/usage?days=30').then(function(data){\nvar html='<div style=\"margin-bottom:20px\"><h4 style=\"margin-bottom:12px\">📊 30天使用趋势</h4>';\nif(data.daily_usage.length>0){\nvar maxCalls=Math.max.apply(null,data.daily_usage.map(function(d){return d.calls}));\nhtml+='<div style=\"display:flex;align-items:flex-end;gap:4px;height:100px\">';\ndata.daily_usage.forEach(function(d){\nvar height=Math.max(5,(d.calls/maxCalls)*100);\nhtml+='<div style=\"flex:1;background:var(--accent);border-radius:2px 2px 0 0;height:'+height+'px\" title=\"'+d.day+': '+d.calls+'次\"></div>'});\nhtml+='</div>'}\nhtml+='</div>';\nhtml+='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">总调用次数</div><div style=\"font-size:24px;font-weight:600\">'+data.total_calls+'</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">错误率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.error_rate>5?'var(--error)':'var(--success)')+'\">'+data.error_rate+'%</div></div>';\nhtml+='</div>';\nshowCustomModal('📈 使用分析',html,'analyticsModal')\n}).catch(function(e){alert('获取分析失败: '+e.message)})}\n\n// ========== 第三方集成 ==========\nfunction saveIntegration(type){\nvar data={};\nif(type==='slack'){\ndata={slack_token:$('slackToken').value,slack_secret:$('slackSecret').value}\n}else if(type==='feishu'){\ndata={feishu_app_id:$('feishuAppId').value,feishu_secret:$('feishuSecret').value}\n}else if(type==='webhook'){\ndata={webhook_url:$('webhookUrl').value,webhook_new_msg:$('webhookNewMsg').checked,webhook_error:$('webhookError').checked}\n}\nlocalStorage.setItem('integration_'+type,JSON.stringify(data));\nshowToast('配置已保存')}\n\nfunction loadIntegrations(){\ntry{\nvar slack=JSON.parse(localStorage.getItem('integration_slack')||'{}');\nif(slack.slack_token)$('slackToken').value=slack.slack_token;\nif(slack.slack_secret)$('slackSecret').value=slack.slack_secret;\nvar feishu=JSON.parse(localStorage.getItem('integration_feishu')||'{}');\nif(feishu.feishu_app_id)$('feishuAppId').value=feishu.feishu_app_id;\nif(feishu.feishu_secret)$('feishuSecret').value=feishu.feishu_secret;\nvar webhook=JSON.parse(localStorage.getItem('integration_webhook')||'{}');\nif(webhook.webhook_url)$('webhookUrl').value=webhook.webhook_url;\nif(webhook.webhook_new_msg)$('webhookNewMsg').checked=true;\nif(webhook.webhook_error)$('webhookError').checked=true;\n}catch(e){}}\n\nfunction testSlackIntegration(){\nshowToast('测试 Slack 连接...');\napi('/api/integrations/slack/send',{method:'POST',body:JSON.stringify({channel:'#general',text:'AI Hub 测试消息'})}).then(function(data){\nif(data.ok){showToast('Slack 连接成功!')}else{alert('连接失败: '+(data.error||'未知错误'))}\n}).catch(function(e){alert('连接失败: '+e.message)})}\n\nfunction testFeishuIntegration(){\nshowToast('测试飞书连接...');\napi('/api/integrations/feishu/send',{method:'POST',body:JSON.stringify({chat_id:'test',text:'AI Hub 测试消息'})}).then(function(data){\nif(data.code===0){showToast('飞书连接成功!')}else{alert('连接失败: '+(data.msg||'未知错误'))}\n}).catch(function(e){alert('连接失败: '+e.message)})}\n\n// ========== 灰度发布 ==========\nfunction loadFeatureFlags(){\napi('/api/features/all').then(function(data){\nvar html='';\nfor(var name in data){\nvar flag=data[name];\nhtml+='<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\">';\nhtml+='<div><strong>'+name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">灰度比例: '+flag.percentage+'% · 白名单用户: '+(flag.users?flag.users.length:0)+'</div></div>';\nhtml+='<label class=\"switch\"><input type=\"checkbox\" '+(flag.enabled?'checked':'')+' onchange=\"toggleFeatureFlag(\\''+name+'\\',this.checked)\"><span class=\"switch-slider\"></span></label>';\nhtml+='</div>'}\n$('featureFlagsList').innerHTML=html||'<p style=\"color:var(--text2)\">暂无功能开关</p>'\n}).catch(function(e){$('featureFlagsList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction toggleFeatureFlag(name,enabled){\napi('/api/features/'+name,{method:'POST',body:JSON.stringify({enabled:enabled})}).then(function(){\nshowToast(name+(enabled?' 已启用':' 已禁用'))\n}).catch(function(e){alert('操作失败: '+e.message)})}\n\nfunction updateFeatureFlagPercentage(name,percentage){\napi('/api/features/'+name,{method:'POST',body:JSON.stringify({percentage:parseInt(percentage)})}).then(function(){\nshowToast('灰度比例已更新')\n}).catch(function(e){alert('操作失败: '+e.message)})}\n\n// ========== 链路追踪 ==========\nfunction loadTraces(){\napi('/api/traces?limit=50').then(function(data){\nif(data.length===0){$('tracesList').innerHTML='<p style=\"color:var(--text2)\">暂无追踪记录</p>';return}\nvar html='<table style=\"width:100%;border-collapse:collapse;font-size:13px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">ID</th><th style=\"padding:10px\">名称</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">Spans</th></tr>';\ndata.forEach(function(t){\nhtml+='<tr style=\"border-top:1px solid var(--border);cursor:pointer\" onclick=\"showTraceDetail(\\''+t.id+'\\')\">';\nhtml+='<td style=\"padding:10px;font-family:monospace\">'+t.id+'</td>';\nhtml+='<td style=\"padding:10px\">'+t.name+'</td>';\nhtml+='<td style=\"padding:10px;text-align:right\">'+(t.total_duration?(t.total_duration*1000).toFixed(0)+'ms':'-')+'</td>';\nhtml+='<td style=\"padding:10px\">'+(t.spans?t.spans.length:0)+'</td>';\nhtml+='</tr>'});\nhtml+='</table>';\n$('tracesList').innerHTML=html\n}).catch(function(e){$('tracesList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction showTraceDetail(traceId){\napi('/api/traces/'+traceId).then(function(data){\nvar html='<div style=\"margin-bottom:16px\"><strong>Trace ID:</strong> '+data.id+'<br><strong>名称:</strong> '+data.name+'<br><strong>总耗时:</strong> '+(data.total_duration?(data.total_duration*1000).toFixed(0)+'ms':'-')+'</div>';\nif(data.spans&&data.spans.length>0){\nhtml+='<h4 style=\"margin-bottom:12px\">Spans</h4>';\ndata.spans.forEach(function(s,i){\nvar width=Math.min(100,s.duration*100);\nhtml+='<div style=\"margin-bottom:8px\"><div style=\"display:flex;justify-content:space-between;font-size:13px\"><span>'+s.name+'</span><span>'+(s.duration*1000).toFixed(0)+'ms</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;margin-top:4px\"><div style=\"background:var(--accent);height:100%;width:'+width+'%;border-radius:4px\"></div></div></div>'\n})}\nshowCustomModal('🔍 追踪详情',html,'traceDetailModal')\n}).catch(function(e){alert('加载失败: '+e.message)})}\n\nfunction exportTraces(){\napi('/api/traces?limit=100').then(function(data){\nif(data.length===0){alert('暂无追踪记录');return}\nvar traceIds=data.map(function(t){return t.id});\napi('/api/traces/export',{method:'POST',body:JSON.stringify({trace_ids:traceIds,format:'jaeger'})}).then(function(result){\nvar blob=new Blob([JSON.stringify(result.data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='traces_export_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('追踪数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})\n}).catch(function(e){alert('获取追踪失败: '+e.message)})}\n\n// ========== 多 Agent 协作 ==========\nfunction loadAgents(){\napi('/api/agents').then(function(data){\nvar html=data.map(function(a){\nreturn'<label style=\"display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer\"><input type=\"checkbox\" class=\"agent-checkbox\" value=\"'+a.name+'\" checked><span>'+a.name+'</span><span style=\"font-size:11px;color:var(--text2)\">'+a.role+'</span></label>'\n}).join('');\n$('agentCheckboxes').innerHTML=html\n}).catch(function(){})}\n\nfunction runMultiAgent(){\nvar task=$('multiAgentTask').value.trim();\nif(!task){alert('请输入任务描述');return}\nvar agents=[];\ndocument.querySelectorAll('.agent-checkbox:checked').forEach(function(cb){agents.push(cb.value)});\nif(agents.length<2){alert('请至少选择2个Agent');return}\nvar mode=$('agentMode').value;\n$('multiAgentResults').style.display='block';\n$('multiAgentResultsContent').innerHTML='<p style=\"color:var(--text2)\">Agent 正在协作中...</p>';\napi('/api/agents/collaborate',{method:'POST',body:JSON.stringify({task:task,agents:agents,mode:mode})}).then(function(data){\nvar html='<div style=\"font-size:12px;color:var(--text2);margin-bottom:16px\">模式: '+data.mode+'</div>';\nfor(var name in data.results){\nhtml+='<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px;border-left:4px solid var(--accent)\"><div style=\"font-weight:500;margin-bottom:8px\">'+name+'</div><div style=\"font-size:14px;line-height:1.6\">'+marked.parse(data.results[name])+'</div></div>'\n}\n$('multiAgentResultsContent').innerHTML=html\n}).catch(function(e){$('multiAgentResultsContent').innerHTML='<p style=\"color:var(--error)\">执行失败: '+e.message+'</p>'})}\n\nfunction showCreateAgentModal(){\nvar html='<div class=\"form-group\"><label>Agent 名称</label><input type=\"text\" id=\"newAgentName\" placeholder=\"分析师\"></div><div class=\"form-group\"><label>角色描述</label><input type=\"text\" id=\"newAgentRole\" placeholder=\"数据分析专家\"></div><div class=\"form-group\"><label>使用模型</label><input type=\"text\" id=\"newAgentModel\" value=\"gpt-4o-mini\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createAgent()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'agentModal\\')\">取消</button></div>';\nshowCustomModal('创建 Agent',html,'agentModal')}\n\nfunction createAgent(){\nvar name=$('newAgentName').value.trim();\nvar role=$('newAgentRole').value.trim();\nvar model=$('newAgentModel').value.trim()||'gpt-4o-mini';\nif(!name||!role){alert('请填写名称和角色');return}\napi('/api/agents/create',{method:'POST',body:JSON.stringify({name:name,role:role,model:model})}).then(function(){\ncloseModal('agentModal');\nloadAgents();\nshowToast('Agent 已创建')\n}).catch(function(e){alert('创建失败: '+e.message)})}\n\n// ========== 系统监控 ==========\nfunction loadSystemMetrics(){\napi('/api/system/metrics').then(function(data){\n$('cpuUsage').textContent=data.cpu_percent+'%';\n$('cpuUsage').style.color=data.cpu_percent>80?'var(--error)':data.cpu_percent>50?'var(--warning)':'var(--success)';\n$('memoryUsage').textContent=data.memory_percent+'%';\n$('memoryUsage').style.color=data.memory_percent>80?'var(--error)':data.memory_percent>50?'var(--warning)':'var(--success)';\n$('diskUsage').textContent=data.disk_percent+'%';\n$('diskUsage').style.color=data.disk_percent>80?'var(--error)':data.disk_percent>50?'var(--warning)':'var(--success)';\nvar hours=Math.floor(data.uptime/3600);\nvar days=Math.floor(hours/24);\n$('uptimeDisplay').textContent=days>0?days+'d '+hours%24+'h':hours+'h';\n// 性能指标\nvar perfHtml='';\nif(data.performance){\nfor(var name in data.performance){\nvar p=data.performance[name];\nperfHtml+='<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><div style=\"font-weight:500;margin-bottom:8px\">'+name+'</div>';\nperfHtml+='<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:8px;font-size:12px\">';\nperfHtml+='<div>平均: <span style=\"color:var(--accent)\">'+p.avg_ms.toFixed(1)+'ms</span></div>';\nperfHtml+='<div>P99: <span style=\"color:var(--warning)\">'+p.p99_ms.toFixed(1)+'ms</span></div>';\nperfHtml+='<div>调用: <span style=\"color:var(--text2)\">'+p.count+'</span></div>';\nperfHtml+='</div></div>'\n}\n}\n$('performanceMetrics').innerHTML=perfHtml||'<p style=\"color:var(--text2);text-align:center\">暂无性能数据</p>'\n}).catch(function(e){console.error('加载系统指标失败:',e)})}\n\nfunction loadAlerts(){\napi('/api/system/alerts').then(function(data){\nif(data.length===0){$('alertsList').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无告警</p>';return}\nvar html=data.map(function(alert){\nvar color=alert.severity==='critical'?'var(--error)':alert.severity==='warning'?'var(--warning)':'var(--text2)';\nreturn'<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px;border-left:4px solid '+color+'\"><div style=\"display:flex;justify-content:space-between\"><span style=\"font-weight:500\">'+alert.name+'</span><span style=\"font-size:12px;color:var(--text2)\">'+alert.timestamp.slice(11,19)+'</span></div><div style=\"font-size:13px;color:var(--text2);margin-top:4px\">'+alert.message+'</div></div>'\n}).join('');\n$('alertsList').innerHTML=html\n}).catch(function(e){$('alertsList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction loadTraces(){\napi('/api/system/traces?limit=20').then(function(data){\nif(data.length===0){$('tracesList').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无追踪数据</p>';return}\nvar html=data.map(function(trace){\nvar color=trace.status==='OK'?'var(--success)':'var(--error)';\nvar duration=(trace.duration/1000).toFixed(2);\nreturn'<div style=\"padding:10px;background:var(--bg);border-radius:8px;margin-bottom:6px;font-size:13px\"><div style=\"display:flex;justify-content:space-between;align-items:center\"><span style=\"font-weight:500\">'+trace.operationName+'</span><span style=\"color:'+color+'\">'+duration+'ms</span></div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">TraceID: '+trace.traceId.slice(0,8)+'...</div></div>'\n}).join('');\n$('tracesList').innerHTML=html\n}).catch(function(e){$('tracesList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\n// ========== 任务队列 ==========\nfunction loadTaskQueue(){\napi('/api/tasks/stats').then(function(data){\n$('pendingTasks').textContent=data.by_status.pending||0;\n$('runningTasks').textContent=data.by_status.running||0;\n$('completedTasks').textContent=data.by_status.completed||0;\n$('failedTasks').textContent=data.by_status.failed||0;\nloadTasksList();\nloadScheduledJobs()\n}).catch(function(e){console.error('加载任务统计失败:',e)})}\n\nfunction loadTasksList(){\napi('/api/tasks?limit=50').then(function(data){\nif(data.length===0){$('tasksList').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无任务</p>';return}\nvar html=data.map(function(task){\nvar statusColors={pending:'var(--warning)',running:'var(--accent)',completed:'var(--success)',failed:'var(--error)',retrying:'var(--warning)'};\nvar color=statusColors[task.status]||'var(--text2)';\nreturn'<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"display:flex;justify-content:space-between;align-items:center\"><span style=\"font-weight:500\">'+task.name+'</span><span style=\"padding:2px 8px;background:'+color+';color:#fff;border-radius:4px;font-size:11px\">'+task.status+'</span></div><div style=\"font-size:12px;color:var(--text2);margin-top:6px\">ID: '+task.id.slice(0,8)+'... | 创建: '+task.created_at.slice(11,19)+(task.duration_ms?' | 耗时: '+task.duration_ms+'ms':'')+'</div>'+(task.error?'<div style=\"font-size:12px;color:var(--error);margin-top:4px\">错误: '+task.error+'</div>':'')+'</div>'\n}).join('');\n$('tasksList').innerHTML=html\n}).catch(function(e){$('tasksList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction loadScheduledJobs(){\napi('/api/tasks/scheduled').then(function(data){\nif(data.length===0){$('scheduledJobs').innerHTML='<p style=\"color:var(--text2);text-align:center;padding:20px\">暂无定时任务</p>';return}\nvar html=data.map(function(job){\nreturn'<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"display:flex;justify-content:space-between;align-items:center\"><span style=\"font-weight:500\">'+job.name+'</span><span style=\"font-size:12px;color:var(--text2)\">间隔: '+(job.interval/60)+'分钟</span></div><div style=\"font-size:12px;color:var(--text2);margin-top:6px\">执行次数: '+job.run_count+' | 错误: '+job.errors+(job.last_run?' | 上次: '+job.last_run.slice(11,19):'')+'</div></div>'\n}).join('');\n$('scheduledJobs').innerHTML=html\n}).catch(function(e){$('scheduledJobs').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\n// ========== 安全中心 ==========\nfunction loadSecurityStatus(){\napi('/api/security/status').then(function(data){\n$('blockedIpsCount').textContent=data.blocked_ips||0;\n$('failedAttemptsCount').textContent=data.failed_attempts_tracked||0;\n$('twoFaUsersCount').textContent=data['2fa_enabled_users']||0;\nvar score=data.blocked_ips===0&&data.failed_attempts_tracked<10?'A':'B';\n$('securityScore').textContent=score;\n$('securityScore').style.color=score==='A'?'var(--success)':'var(--warning)'\n}).catch(function(e){console.error('加载安全状态失败:',e)})}\n\nfunction unblockIP(){\nvar ip=$('unblockIpInput').value.trim();\nif(!ip){alert('请输入IP地址');return}\nif(!confirm('确定解封 '+ip+'?'))return;\napi('/api/security/unblock-ip',{method:'POST',body:JSON.stringify({ip:ip})}).then(function(){\nshowToast('IP已解封');\n$('unblockIpInput').value='';\nloadSecurityStatus()\n}).catch(function(e){alert('解封失败: '+e.message)})}\n\n// ========== 本地模型 (Ollama) ==========\nfunction loadOllamaModels(){\n$('ollamaStatus').innerHTML='<span style=\"color:var(--text2)\">检查 Ollama 连接...</span>';\napi('/api/ollama/models').then(function(data){\nif(data.error){\n$('ollamaStatus').innerHTML='<span style=\"color:var(--error)\">❌ '+data.error+'</span>';\n$('ollamaModelList').innerHTML='';\n$('ollamaModelSelect').innerHTML='<option>无可用模型</option>';\nreturn}\n$('ollamaStatus').innerHTML='<span style=\"color:var(--success)\">✅ Ollama 已连接,共 '+data.models.length+' 个模型</span>';\nvar html=data.models.map(function(m){\nvar size=(m.size/1024/1024/1024).toFixed(1);\nreturn'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div><strong>'+m.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+size+' GB</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"selectOllamaModel(\\''+m.name+'\\')\">使用</button></div>'\n}).join('');\n$('ollamaModelList').innerHTML=html||'<p style=\"color:var(--text2)\">暂无模型,请先拉取</p>';\nvar selectHtml=data.models.map(function(m){return'<option value=\"'+m.name+'\">'+m.name+'</option>'}).join('');\n$('ollamaModelSelect').innerHTML=selectHtml||'<option>无可用模型</option>'\n}).catch(function(e){$('ollamaStatus').innerHTML='<span style=\"color:var(--error)\">❌ 连接失败</span>'})}\n\nfunction showPullModelModal(){\nvar html='<div class=\"form-group\"><label>模型名称</label><input type=\"text\" id=\"pullModelName\" placeholder=\"llama2, mistral, codellama...\"></div><p style=\"font-size:12px;color:var(--text2);margin-bottom:16px\">常用模型: llama2, mistral, codellama, phi, gemma</p><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"pullOllamaModel()\">拉取</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pullModal\\')\">取消</button></div>';\nshowCustomModal('拉取 Ollama 模型',html,'pullModal')}\n\nfunction pullOllamaModel(){\nvar model=$('pullModelName').value.trim();\nif(!model){alert('请输入模型名称');return}\nshowToast('开始拉取 '+model+',请稍候...');\ncloseModal('pullModal');\napi('/api/ollama/pull',{method:'POST',body:JSON.stringify({model:model})}).then(function(data){\nif(data.success){showToast('模型拉取成功!');loadOllamaModels()}else{alert('拉取失败')}\n}).catch(function(e){alert('拉取失败: '+e.message)})}\n\nfunction selectOllamaModel(name){$('ollamaModelSelect').value=name;showToast('已选择 '+name)}\n\nfunction chatWithOllama(){\nvar model=$('ollamaModelSelect').value;\nvar message=$('ollamaMessage').value.trim();\nif(!model||!message){alert('请选择模型并输入消息');return}\n$('ollamaResponse').style.display='block';\n$('ollamaResponse').innerHTML='<p style=\"color:var(--text2)\">思考中...</p>';\napi('/api/ollama/chat',{method:'POST',body:JSON.stringify({model:model,messages:[{role:'user',content:message}]})}).then(function(data){\nvar content=data.message?data.message.content:'无响应';\n$('ollamaResponse').innerHTML=marked.parse(content)\n}).catch(function(e){$('ollamaResponse').innerHTML='<p style=\"color:var(--error)\">错误: '+e.message+'</p>'})}\n\nfunction loadVLLMModels(){\nvar url=$('vllmUrl').value.trim();\n$('vllmStatus').innerHTML='<span style=\"color:var(--text2)\">检查连接...</span>';\nfetch(url+'/v1/models').then(function(r){return r.json()}).then(function(data){\nif(data.data&&data.data.length>0){\n$('vllmStatus').innerHTML='<span style=\"color:var(--success)\">✅ vLLM 已连接,模型: '+data.data.map(function(m){return m.id}).join(', ')+'</span>'\n}else{\n$('vllmStatus').innerHTML='<span style=\"color:var(--warning)\">⚠️ 已连接但无模型</span>'\n}\n}).catch(function(){$('vllmStatus').innerHTML='<span style=\"color:var(--error)\">❌ 无法连接到 vLLM</span>'})}\n\n// ========== RAG 检索 ==========\nfunction loadRAGKnowledgeBases(){\napi('/api/knowledge-bases').then(function(data){\nvar html='<option value=\"\">选择知识库</option>';\ndata.forEach(function(kb){html+='<option value=\"'+kb.id+'\">'+kb.name+'</option>'});\n$('ragKbSelect').innerHTML=html\n}).catch(function(){})}\n\nfunction searchRAG(){\nvar kbId=$('ragKbSelect').value;\nvar query=$('ragQuery').value.trim();\nif(!kbId){alert('请选择知识库');return}\nif(!query){alert('请输入问题');return}\n$('ragResults').innerHTML='<p style=\"color:var(--text2)\">搜索中...</p>';\napi('/api/rag/search',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),query:query,top_k:5})}).then(function(data){\nif(data.results.length===0){$('ragResults').innerHTML='<p style=\"color:var(--text2)\">未找到相关内容</p>';return}\nvar html=data.results.map(function(r,i){\nreturn'<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px;border-left:4px solid var(--accent)\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span style=\"font-weight:500\">#'+(i+1)+' '+r.chunk_id+'</span><span style=\"color:var(--accent)\">相似度: '+(r.score*100).toFixed(1)+'%</span></div><div style=\"font-size:14px;color:var(--text2);line-height:1.6\">'+r.content.slice(0,300)+(r.content.length>300?'...':'')+'</div></div>'\n}).join('');\n$('ragResults').innerHTML=html\n}).catch(function(e){$('ragResults').innerHTML='<p style=\"color:var(--error)\">搜索失败: '+e.message+'</p>'})}\n\nfunction chatWithRAG(){\nvar kbId=$('ragKbSelect').value;\nvar query=$('ragQuery').value.trim();\nif(!kbId){alert('请选择知识库');return}\nif(!query){alert('请输入问题');return}\n$('ragResults').innerHTML='<p style=\"color:var(--text2)\">AI 正在思考...</p>';\napi('/api/rag/chat',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),question:query})}).then(function(data){\nvar html='<div style=\"padding:20px;background:var(--bg);border-radius:12px\"><div style=\"font-size:14px;line-height:1.8\">'+marked.parse(data.answer)+'</div>';\nif(data.sources&&data.sources.length>0){\nhtml+='<div style=\"margin-top:16px;padding-top:16px;border-top:1px solid var(--border)\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:8px\">参考来源:</div>';\ndata.sources.forEach(function(s){html+='<span class=\"tag\" style=\"margin-right:8px\">'+s.chunk_id+' ('+(s.score*100).toFixed(0)+'%)</span>'});\nhtml+='</div>'}\nhtml+='</div>';\n$('ragResults').innerHTML=html\n}).catch(function(e){$('ragResults').innerHTML='<p style=\"color:var(--error)\">对话失败: '+e.message+'</p>'})}\n\nfunction indexDocument(){\nvar kbId=$('ragKbSelect').value;\nvar content=$('ragContent').value.trim();\nvar filename=$('ragFilename').value.trim()||'document.txt';\nif(!kbId){alert('请选择知识库');return}\nif(!content){alert('请输入文档内容');return}\nshowToast('正在索引文档...');\napi('/api/rag/index',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),content:content,filename:filename})}).then(function(data){\nshowToast('索引完成,共 '+data.indexed_chunks+' 个分块');\n$('ragContent').value='';\n$('ragFilename').value=''\n}).catch(function(e){alert('索引失败: '+e.message)})}\n\n// ========== 计费系统 ==========\nfunction loadBillingPlans(){\napi('/api/billing/plans').then(function(data){\nvar html=data.map(function(p){\nvar features=JSON.parse(p.features||'[]');\nreturn'<div class=\"price-card\" onclick=\"subscribePlan(\\''+p.id+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">¥'+p.price+'<span>/月</span></div><ul>'+features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn btn-primary\" style=\"width:100%\">选择</button></div>'\n}).join('');\n$('billingPlans').innerHTML=html\n}).catch(function(){})}\n\nfunction loadSubscription(){\napi('/api/billing/subscription').then(function(data){\n$('currentPlanName').textContent=data.plan_name||data.plan||'免费版';\nvar remaining=data.tokens_limit===-1?'无限':formatNumber(data.tokens_limit||10000);\n$('remainingQuota').textContent=remaining\n}).catch(function(){})}\n\nfunction loadUsageStats(){\napi('/api/billing/usage?period=month').then(function(data){\nvar html='';\nfor(var type in data.usage){\nvar u=data.usage[type];\nhtml+='<div style=\"padding:16px;background:var(--bg);border-radius:10px;text-align:center\"><div style=\"font-size:24px;font-weight:600;color:var(--accent)\">'+formatNumber(u.amount)+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+type+'</div><div style=\"font-size:11px;color:var(--success);margin-top:4px\">¥'+u.cost.toFixed(2)+'</div></div>'\n}\n$('usageStats').innerHTML=html||'<p style=\"color:var(--text2);grid-column:1/-1;text-align:center\">暂无用量数据</p>'\n}).catch(function(){})}\n\nfunction loadInvoices(){\napi('/api/billing/invoices').then(function(data){\nif(data.length===0){$('invoiceList').innerHTML='<p style=\"color:var(--text2)\">暂无发票</p>';return}\nvar html=data.map(function(inv){\nvar statusColor=inv.status==='paid'?'var(--success)':'var(--warning)';\nreturn'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div><div style=\"font-weight:500\">'+inv.id+'</div><div style=\"font-size:12px;color:var(--text2)\">'+(inv.created_at||'').slice(0,10)+'</div></div><div style=\"text-align:right\"><div style=\"font-weight:600\">¥'+inv.amount+'</div><div style=\"font-size:12px;color:'+statusColor+'\">'+(inv.status==='paid'?'已支付':'待支付')+'</div></div>'+(inv.status!=='paid'?'<button class=\"btn btn-primary btn-sm\" onclick=\"payInvoice(\\''+inv.id+'\\')\">支付</button>':'')+'</div>'\n}).join('');\n$('invoiceList').innerHTML=html\n}).catch(function(){})}\n\nfunction subscribePlan(planId){\nif(!authToken){alert('请先登录');return}\nif(!confirm('确定订阅此套餐?'))return;\napi('/api/billing/subscribe',{method:'POST',body:JSON.stringify({plan_id:planId,months:1})}).then(function(data){\nshowToast('订阅成功,请支付发票');\nloadInvoices();\nloadSubscription()\n}).catch(function(e){alert('订阅失败: '+e.message)})}\n\nfunction payInvoice(invoiceId){\nif(!confirm('确定支付?'))return;\napi('/api/billing/pay/'+invoiceId,{method:'POST',body:JSON.stringify({method:'alipay'})}).then(function(){\nshowToast('支付成功!');\nloadInvoices();\nloadSubscription()\n}).catch(function(e){alert('支付失败: '+e.message)})}\n\n// ========== RBAC 权限 ==========\nfunction loadMyPermissions(){\napi('/api/rbac/my-permissions').then(function(data){\nvar html=data.permissions.map(function(p){\nreturn'<span class=\"tag tag-primary\">'+p+'</span>'\n}).join('');\n$('myPermissions').innerHTML=html||'<span style=\"color:var(--text2)\">暂无权限</span>'\n}).catch(function(){})}\n\nfunction loadRoles(){\napi('/api/rbac/roles').then(function(data){\nvar html=data.map(function(r){\nvar perms=JSON.parse(r.permissions||'[]');\nreturn'<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong>'+r.name+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.description+'</span></div><div style=\"display:flex;flex-wrap:wrap;gap:6px\">'+perms.map(function(p){return'<span class=\"tag\">'+p+'</span>'}).join('')+'</div></div>'\n}).join('');\n$('rolesList').innerHTML=html\n}).catch(function(){})}\n\nfunction showCreateRoleModal(){\nvar html='<div class=\"form-group\"><label>角色名称</label><input type=\"text\" id=\"newRoleName\" placeholder=\"role_name\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"newRoleDesc\" placeholder=\"角色描述\"></div><div class=\"form-group\"><label>权限(逗号分隔)</label><input type=\"text\" id=\"newRolePerms\" placeholder=\"chat,notes,memory\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createRole()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'roleModal\\')\">取消</button></div>';\nshowCustomModal('创建角色',html,'roleModal')}\n\nfunction createRole(){\nvar name=$('newRoleName').value.trim();\nvar desc=$('newRoleDesc').value.trim();\nvar perms=$('newRolePerms').value.split(',').map(function(p){return p.trim()}).filter(function(p){return p});\nif(!name){alert('请输入角色名称');return}\napi('/api/rbac/roles',{method:'POST',body:JSON.stringify({name:name,description:desc,permissions:perms})}).then(function(){\ncloseModal('roleModal');\nloadRoles();\nshowToast('角色已创建')\n}).catch(function(e){alert('创建失败: '+e.message)})}\n\n// 初始化时加载推荐\nsetTimeout(loadRecommendations,1000);\nsetTimeout(loadIntegrations,100);\n\n// ========== 快捷键帮助 ==========\nfunction showHotkeyHelp(){\nvar html='<div style=\"display:grid;gap:8px\">';\nvar hotkeys=[\n['Ctrl + N','新建对话'],\n['Ctrl + K','全局搜索'],\n['Ctrl + D','切换主题'],\n['Ctrl + H','系统状态'],\n['Ctrl + B','批量选择'],\n['Ctrl + F','搜索当前对话'],\n['Ctrl + /','快捷键帮助'],\n['Enter','发送消息'],\n['Shift + Enter','换行'],\n['Escape','关闭弹窗']\n];\nhotkeys.forEach(function(h){\nhtml+='<div class=\"hotkey-help-item\"><span>'+h[1]+'</span><span class=\"hotkey-help-key\">'+h[0]+'</span></div>'\n});\nhtml+='</div>';\nshowCustomModal('⌨️ 快捷键帮助',html,'hotkeyHelpModal')}\n\n// ========== 欢迎引导 ==========\nfunction showWelcomeGuide(){\nif(localStorage.getItem('welcomeShown'))return;\nvar html='<div style=\"text-align:center;padding:20px\"><div style=\"font-size:48px;margin-bottom:16px\">🤖</div><h2 style=\"margin-bottom:12px\">欢迎使用 AI Hub</h2><p style=\"color:var(--text2);margin-bottom:24px\">一站式 AI 平台,支持多模型、多功能</p><div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:12px;text-align:left;margin-bottom:24px\"><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">💬</span><div style=\"font-weight:500;margin-top:8px\">多模型对话</div><div style=\"font-size:12px;color:var(--text2)\">支持 OpenAI、Claude、Gemini 等</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">🎨</span><div style=\"font-weight:500;margin-top:8px\">图片生成</div><div style=\"font-size:12px;color:var(--text2)\">DALL-E 3 AI 绘图</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">📚</span><div style=\"font-weight:500;margin-top:8px\">知识库</div><div style=\"font-size:12px;color:var(--text2)\">上传文档,智能问答</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">👥</span><div style=\"font-weight:500;margin-top:8px\">团队协作</div><div style=\"font-size:12px;color:var(--text2)\">多人共享对话和资源</div></div></div><button class=\"btn btn-primary\" onclick=\"closeModal(\\'welcomeModal\\');localStorage.setItem(\\'welcomeShown\\',\\'1\\')\">开始使用</button></div>';\nshowCustomModal('',html,'welcomeModal')}\nsetTimeout(showWelcomeGuide,500);\n\nconsole.log('🤖 AI Hub v2.0.0 - Enhanced');\n</script>\n</body>\n</html>\n"}, "20d3f95d96806ba21fa2391d55071621234ed68d": {"t": 1785765459.334548, "n": 242810, "h": "5b016708236f4a4b", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"theme-color\" content=\"#0f0f1a\">\n<meta name=\"description\" content=\"AI Hub - 统一 AI 平台\">\n<link rel=\"manifest\" href=\"/static/manifest.json\">\n<link rel=\"apple-touch-icon\" href=\"/static/icon-192.png\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"local-models\"><span class=\"nav-item-icon\">🏠</span> 本地模型</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"traces\"><span class=\"nav-item-icon\">🔍</span> 链路追踪</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n<div class=\"nav-item\" data-page=\"rag\"><span class=\"nav-item-icon\">🔍</span> RAG 检索</div>\n<div class=\"nav-item\" data-page=\"billing\"><span class=\"nav-item-icon\">💳</span> 订阅计费</div>\n<div class=\"nav-item\" data-page=\"rbac\"><span class=\"nav-item-icon\">🛡️</span> 权限管理</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"integrations\"><span class=\"nav-item-icon\">🔗</span> 第三方集成</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"workflows\"><span class=\"nav-item-icon\">🤖</span> Agent 工作流</div>\n<div class=\"nav-item\" data-page=\"code-runner\"><span class=\"nav-item-icon\">▶️</span> 代码运行</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" onclick=\"showHealthDashboard()\"><span class=\"nav-item-icon\">🖥️</span> 系统状态</div>\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\" title=\"批量操作\">☑️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div id=\"batchActions\" style=\"display:none;padding:8px;background:var(--bg3);gap:8px;align-items:center\">\n<span style=\"font-size:12px\">已选 <span id=\"selectedCount\">0</span> 个</span>\n<button class=\"btn btn-danger btn-sm\" onclick=\"batchDeleteChats()\">删除</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"batchExportChats()\">导出</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\">取消</button>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"quickReplies\" style=\"display:none;padding:8px 0;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap\"></div>\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateImage()\" title=\"生成图片\">🎨</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateMindmap()\" title=\"生成思维导图\">🧠</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"saveAsTemplate()\" title=\"保存为模板\">💾</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 本地模型页 -->\n<div id=\"page-local-models\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🏠</span> 本地模型 (Ollama)</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">使用 Ollama 运行本地大语言模型,数据完全私有</p>\n<div style=\"display:flex;gap:12px;margin-bottom:20px\">\n<button class=\"btn btn-primary\" onclick=\"loadOllamaModels()\">🔄 刷新模型</button>\n<button class=\"btn btn-ghost\" onclick=\"showPullModelModal()\">📥 拉取模型</button>\n<a href=\"https://ollama.ai\" target=\"_blank\" class=\"btn btn-ghost\">📖 Ollama 官网</a>\n</div>\n<div id=\"ollamaStatus\" style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:16px\"></div>\n<div id=\"ollamaModelList\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 本地模型对话</h4>\n<div class=\"form-group\"><label>选择模型</label><select id=\"ollamaModelSelect\" style=\"width:100%;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select></div>\n<div class=\"form-group\"><label>消息</label><textarea id=\"ollamaMessage\" rows=\"4\" placeholder=\"输入消息...\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"chatWithOllama()\">发送</button>\n<div id=\"ollamaResponse\" style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:8px;min-height:100px;display:none\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚡</span> vLLM 服务</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">高性能推理服务器</p>\n<div class=\"form-group\"><label>vLLM 地址</label><input type=\"text\" id=\"vllmUrl\" value=\"http://localhost:8080\" placeholder=\"http://localhost:8080\"></div>\n<button class=\"btn btn-ghost\" onclick=\"loadVLLMModels()\">检查连接</button>\n<div id=\"vllmStatus\" style=\"margin-top:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">双因素认证 (2FA)<br><small style=\"color:var(--text2)\">使用 Google Authenticator 等应用增强账户安全</small></div><div style=\"display:flex;gap:8px\"><span id=\"2faStatus\" style=\"color:var(--text2)\">未启用</span><button class=\"btn btn-ghost btn-sm\" onclick=\"setup2FA()\" id=\"2faBtn\">设置</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录设备管理</div><button class=\"btn btn-ghost btn-sm\" onclick=\"alert('功能开发中')\">查看设备</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">修改密码</div><button class=\"btn btn-ghost btn-sm\" onclick=\"showChangePasswordModal()\">修改</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复<br><small style=\"color:var(--text2)\">导出/导入所有数据(对话、笔记、记忆、设置)</small></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-primary\" onclick=\"exportAllData()\">📤 导出全部</button><button class=\"btn btn-ghost\" onclick=\"importAllData()\">📥 导入数据</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据库优化<br><small style=\"color:var(--text2)\">清理过期数据,优化数据库性能</small></div><button class=\"btn btn-ghost\" onclick=\"optimizeDatabase()\">🔧 优化数据库</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n<button class=\"btn btn-primary\" onclick=\"showUsageAnalytics()\">📈 详细分析</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 链路追踪页 -->\n<div id=\"page-traces\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔍</span> 链路追踪</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"loadTraces()\">🔄 刷新</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportTraces()\">📥 导出</button>\n</div>\n</div>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:20px\">监控 API 请求的完整调用链路,分析性能瓶颈</p>\n<div id=\"tracesList\"><p style=\"color:var(--text2)\">点击刷新加载追踪记录</p></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 性能概览</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--accent)\" id=\"traceAvgLatency\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">平均延迟</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--success)\" id=\"traceSuccessRate\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">成功率</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--warning)\" id=\"traceCount\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总追踪数</div>\n</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- RAG 检索页 -->\n<div id=\"page-rag\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> RAG 语义检索</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">基于向量的语义搜索,让 AI 理解你的文档内容</p>\n<div class=\"form-group\"><label>选择知识库</label><select id=\"ragKbSelect\" style=\"width:100%;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select></div>\n<div class=\"form-group\"><label>搜索问题</label><input type=\"text\" id=\"ragQuery\" placeholder=\"输入你的问题...\"></div>\n<button class=\"btn btn-primary\" onclick=\"searchRAG()\">🔍 语义搜索</button>\n<button class=\"btn btn-ghost\" onclick=\"chatWithRAG()\" style=\"margin-left:8px\">💬 RAG 对话</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 搜索结果</h4>\n<div id=\"ragResults\" style=\"min-height:100px\"><p style=\"color:var(--text2)\">输入问题后点击搜索</p></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📤</span> 索引文档</h4>\n<div class=\"form-group\"><label>文档内容</label><textarea id=\"ragContent\" rows=\"6\" placeholder=\"粘贴文档内容...\"></textarea></div>\n<div class=\"form-group\"><label>文件名</label><input type=\"text\" id=\"ragFilename\" placeholder=\"document.txt\"></div>\n<button class=\"btn btn-primary\" onclick=\"indexDocument()\">📥 索引文档</button>\n</div>\n</div></div></div></div>\n<!-- 订阅计费页 -->\n<div id=\"page-billing\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💳</span> 订阅计费</h4>\n<div id=\"currentSubscription\" style=\"padding:20px;background:var(--bg);border-radius:12px;margin-bottom:20px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div><div style=\"font-size:12px;color:var(--text2)\">当前套餐</div><div style=\"font-size:24px;font-weight:600\" id=\"currentPlanName\">免费版</div></div>\n<div style=\"text-align:right\"><div style=\"font-size:12px;color:var(--text2)\">剩余额度</div><div style=\"font-size:24px;font-weight:600;color:var(--accent)\" id=\"remainingQuota\">10,000</div></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 套餐选择</h4>\n<div id=\"billingPlans\" class=\"price-cards\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 用量统计</h4>\n<div id=\"usageStats\" style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🧾</span> 发票记录</h4>\n<div id=\"invoiceList\"></div>\n</div>\n</div></div></div></div>\n<!-- 权限管理页 -->\n<div id=\"page-rbac\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🛡️</span> 权限管理</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">基于角色的访问控制 (RBAC)</p>\n<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<div style=\"font-size:12px;color:var(--text2);margin-bottom:8px\">我的权限</div>\n<div id=\"myPermissions\" style=\"display:flex;flex-wrap:wrap;gap:8px\"></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👥</span> 角色列表</h4>\n<div id=\"rolesList\"></div>\n<button class=\"btn btn-ghost\" onclick=\"showCreateRoleModal()\" style=\"margin-top:12px\">+ 创建角色</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> 权限说明</h4>\n<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:12px;font-size:13px\">\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>chat</strong> - 对话功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>notes</strong> - 笔记功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>memory</strong> - 全局记忆</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>image</strong> - 图片生成</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>code</strong> - 代码运行</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>rag</strong> - RAG 检索</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>admin</strong> - 管理功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>*</strong> - 所有权限</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- 第三方集成页 -->\n<div id=\"page-integrations\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔗</span> 第三方集成</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:20px\">连接 Slack、飞书等平台,让 AI 助手无处不在</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> Slack 集成</h4>\n<div class=\"form-group\"><label>Bot Token</label><input type=\"password\" id=\"slackToken\" placeholder=\"xoxb-...\" onchange=\"saveIntegration('slack')\"></div>\n<div class=\"form-group\"><label>Signing Secret</label><input type=\"password\" id=\"slackSecret\" placeholder=\"签名密钥\" onchange=\"saveIntegration('slack')\"></div>\n<div class=\"form-group\"><label>Webhook URL</label><div style=\"display:flex;gap:8px\"><input type=\"text\" value=\"http://localhost:8000/api/integrations/slack/webhook\" readonly style=\"flex:1;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText(this.previousElementSibling.value)\">📋</button></div></div>\n<div style=\"display:flex;gap:12px;margin-top:16px\">\n<button class=\"btn btn-primary\" onclick=\"testSlackIntegration()\">🧪 测试连接</button>\n<button class=\"btn btn-ghost\" onclick=\"window.open('https://api.slack.com/apps','_blank')\">📖 创建 Slack App</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐦</span> 飞书集成</h4>\n<div class=\"form-group\"><label>App ID</label><input type=\"text\" id=\"feishuAppId\" placeholder=\"cli_...\" onchange=\"saveIntegration('feishu')\"></div>\n<div class=\"form-group\"><label>App Secret</label><input type=\"password\" id=\"feishuSecret\" placeholder=\"应用密钥\" onchange=\"saveIntegration('feishu')\"></div>\n<div class=\"form-group\"><label>Webhook URL</label><div style=\"display:flex;gap:8px\"><input type=\"text\" value=\"http://localhost:8000/api/integrations/feishu/webhook\" readonly style=\"flex:1;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText(this.previousElementSibling.value)\">📋</button></div></div>\n<div style=\"display:flex;gap:12px;margin-top:16px\">\n<button class=\"btn btn-primary\" onclick=\"testFeishuIntegration()\">🧪 测试连接</button>\n<button class=\"btn btn-ghost\" onclick=\"window.open('https://open.feishu.cn/app','_blank')\">📖 创建飞书应用</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> Webhook 通知</h4>\n<div class=\"form-group\"><label>通知 URL</label><input type=\"text\" id=\"webhookUrl\" placeholder=\"https://your-server.com/webhook\" onchange=\"saveIntegration('webhook')\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">新消息通知</div><label class=\"switch\"><input type=\"checkbox\" id=\"webhookNewMsg\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">错误通知</div><label class=\"switch\"><input type=\"checkbox\" id=\"webhookError\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🎛️</span> 灰度发布</h4>\n<div id=\"featureFlagsList\"></div>\n<button class=\"btn btn-ghost\" onclick=\"loadFeatureFlags()\" style=\"margin-top:12px\">🔄 刷新</button>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Agent 工作流页 -->\n<div id=\"page-workflows\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🤖</span> Agent 工作流</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建多步骤自动化任务,让 AI 按流程完成复杂工作</p>\n<div id=\"workflowTemplates\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👥</span> 多 Agent 协作</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">多个 AI Agent 协同完成复杂任务</p>\n<div class=\"form-group\"><label>任务描述</label><textarea id=\"multiAgentTask\" rows=\"3\" placeholder=\"描述你需要完成的任务...\"></textarea></div>\n<div class=\"form-group\"><label>选择 Agent</label>\n<div id=\"agentCheckboxes\" style=\"display:flex;flex-wrap:wrap;gap:12px\"></div>\n</div>\n<div class=\"form-group\"><label>协作模式</label>\n<select id=\"agentMode\" style=\"width:200px;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\">\n<option value=\"sequential\">顺序执行</option>\n<option value=\"parallel\">并行执行</option>\n<option value=\"debate\">辩论模式</option>\n</select>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runMultiAgent()\">🚀 开始协作</button>\n<button class=\"btn btn-ghost\" onclick=\"showCreateAgentModal()\" style=\"margin-left:8px\">+ 创建 Agent</button>\n</div>\n<div class=\"settings-section\" id=\"multiAgentResults\" style=\"display:none\">\n<h4><span>📋</span> 协作结果</h4>\n<div id=\"multiAgentResultsContent\"></div>\n</div>\n<div class=\"settings-section\" id=\"workflowRunner\" style=\"display:none\">\n<h4><span>▶️</span> 运行工作流</h4>\n<div id=\"workflowInputs\"></div>\n<button class=\"btn btn-primary\" onclick=\"executeWorkflow()\">🚀 执行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('workflowRunner').style.display='none'\">取消</button>\n</div>\n<div class=\"settings-section\" id=\"workflowResults\" style=\"display:none\">\n<h4><span>📋</span> 执行结果</h4>\n<div id=\"workflowResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 代码运行器页 -->\n<div id=\"page-code-runner\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>▶️</span> 代码运行器</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">在线运行 Python / JavaScript 代码</p>\n<div class=\"form-group\">\n<label>语言</label>\n<select id=\"codeLanguage\" style=\"width:150px\">\n<option value=\"python\">Python</option>\n<option value=\"javascript\">JavaScript</option>\n</select>\n</div>\n<div class=\"form-group\">\n<label>代码</label>\n<textarea id=\"codeInput\" rows=\"12\" style=\"font-family:monospace;font-size:13px\" placeholder=\"# 输入代码...\nprint('Hello, World!')\"></textarea>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-primary\" onclick=\"runCode()\">▶️ 运行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('codeInput').value=''\">清空</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 输出结果</h4>\n<pre id=\"codeOutput\" style=\"background:var(--bg);padding:16px;border-radius:8px;min-height:100px;font-family:monospace;font-size:13px;white-space:pre-wrap\">等待运行...</pre>\n</div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>系统状态</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + H</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量选择模式</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + B</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量导出</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>搜索当前对话</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + F</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换主题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + D</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><div class=\"form-group\" id=\"auth2FAGroup\" style=\"display:none\"><label>2FA 验证码</label><input type=\"text\" id=\"auth2FACode\" placeholder=\"6位验证码\" maxlength=\"6\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><div style=\"display:flex;align-items:center;margin:16px 0\"><div style=\"flex:1;height:1px;background:var(--border)\"></div><span style=\"padding:0 12px;color:var(--text2);font-size:12px\">或</span><div style=\"flex:1;height:1px;background:var(--border)\"></div></div><button class=\"btn btn-ghost\" style=\"width:100%;display:flex;align-items:center;justify-content:center;gap:8px\" onclick=\"loginWithGithub()\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg> 使用 GitHub 登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();if(n.dataset.page==='workflows')loadWorkflowTemplates();if(n.dataset.page==='traces')loadTraces();if(n.dataset.page==='integrations')loadFeatureFlags();if(n.dataset.page==='rag')loadRAGKnowledgeBases();if(n.dataset.page==='billing'){loadBillingPlans();loadSubscription();loadUsageStats();loadInvoices()}if(n.dataset.page==='rbac'){loadMyPermissions();loadRoles()}if(n.dataset.page==='local-models')loadOllamaModels();if(n.dataset.page==='workflows')loadAgents();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{\n// 先显示置顶的对话\nvar pinnedChats=chats.filter(function(c){return c.pinned});\nvar normalChats=chats.filter(function(c){return !c.pinned&&!c.archived});\nif(pinnedChats.length>0){html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2)\">📌 置顶</div>';pinnedChats.forEach(function(c){html+=renderChatItem(c)})}\nif(normalChats.length>0){if(pinnedChats.length>0)html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2);margin-top:8px\">💬 对话</div>';normalChats.forEach(function(c){html+=renderChatItem(c)})}}$('chatList').innerHTML=html}\nfunction renderChatItem(c){var selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';var checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';var pinIcon=c.pinned?'📌':'💬';return'<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" style=\"'+selected+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">'+pinIcon+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"favoriteMessageByIndex('+i+')\" title=\"收藏\">❤️</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll();showQuickReplies()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var chat=chats.find(function(c){return c.id===id});var pinText=chat&&chat.pinned?'📌 取消置顶':'📌 置顶';var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"togglePinChat(\\''+id+'\\')\">'+pinText+'</div><div onclick=\"archiveChat(\\''+id+'\\')\">📦 归档</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction togglePinChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.pinned=!chat.pinned;saveChats();renderChats();showToast(chat.pinned?'已置顶':'已取消置顶');if(authToken){api('/api/conversations/'+id+'/pin',{method:'POST'}).catch(function(){})}}\nfunction archiveChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.archived=true;chats=chats.filter(function(c){return c.id!==id});saveChats();renderChats();showToast('已归档');if(authToken){api('/api/conversations/'+id+'/archive',{method:'POST'}).catch(function(){})}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Agent 工作流\nvar workflowTemplates=[];\nvar currentWorkflow=null;\nfunction loadWorkflowTemplates(){api('/api/workflows/templates').then(function(data){workflowTemplates=data;renderWorkflowTemplates()}).catch(function(e){console.error('加载工作流失败:',e)})}\nfunction renderWorkflowTemplates(){var html=workflowTemplates.map(function(w){return'<div style=\"background:var(--bg);border-radius:12px;padding:20px;cursor:pointer\" onclick=\"selectWorkflow(\\''+w.id+'\\')\"><div style=\"display:flex;align-items:center;gap:12px;margin-bottom:12px\"><span style=\"font-size:24px\">🤖</span><div><strong>'+w.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+w.steps.length+' 个步骤</div></div></div><p style=\"font-size:13px;color:var(--text2);line-height:1.5\">'+w.description+'</p></div>'}).join('');$('workflowTemplates').innerHTML=html||'<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无工作流模板</div>'}\nfunction selectWorkflow(id){currentWorkflow=workflowTemplates.find(function(w){return w.id===id});if(!currentWorkflow)return;var inputs=[];currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')&&inputs.indexOf(key)===-1)inputs.push(key)})}});var html=inputs.map(function(key){return'<div class=\"form-group\"><label>'+key+'</label><textarea id=\"wf_'+key+'\" rows=\"3\" placeholder=\"输入 '+key+'\"></textarea></div>'}).join('');$('workflowInputs').innerHTML='<h5 style=\"margin-bottom:16px\">'+currentWorkflow.name+'</h5>'+html;$('workflowRunner').style.display='block';$('workflowResults').style.display='none'}\nfunction executeWorkflow(){if(!currentWorkflow){alert('请先选择工作流');return}var inputData={};currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')){var el=$('wf_'+key);if(el)inputData[key]=el.value}})}});$('workflowResultsContent').innerHTML='<div style=\"text-align:center;padding:40px\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px;color:var(--text2)\">正在执行工作流...</p></div>';$('workflowResults').style.display='block';api('/api/workflows/run',{method:'POST',body:JSON.stringify({name:currentWorkflow.name,steps:currentWorkflow.steps,input_data:inputData})}).then(function(data){var html='';for(var key in data.results){html+='<div style=\"background:var(--bg);border-radius:10px;padding:16px;margin-bottom:12px\"><div style=\"font-weight:600;margin-bottom:8px;color:var(--accent)\">'+key+'</div><div style=\"font-size:14px;line-height:1.6;white-space:pre-wrap\">'+data.results[key]+'</div></div>'}$('workflowResultsContent').innerHTML=html}).catch(function(e){$('workflowResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">执行失败: '+e.message+'</div>'})}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// GitHub 登录\nfunction loginWithGithub(){window.location.href='/api/auth/github'}\n// 2FA 设置\nfunction setup2FA(){if(!authToken){alert('请先登录');return}api('/api/auth/2fa/setup',{method:'POST'}).then(function(data){var html='<div style=\"text-align:center\"><img src=\"'+data.qr_code+'\" style=\"width:200px;height:200px;border-radius:8px\"><p style=\"margin:16px 0;color:var(--text2);font-size:13px\">使用 Google Authenticator 扫描二维码</p><div class=\"form-group\"><label>输入6位验证码确认</label><input type=\"text\" id=\"verify2FACode\" placeholder=\"000000\" maxlength=\"6\" style=\"text-align:center;font-size:20px;letter-spacing:8px\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"verify2FA()\">确认启用</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'2faModal\\')\">取消</button></div></div>';showCustomModal('设置双因素认证',html,'2faModal')}).catch(function(e){alert('设置失败: '+e.message)})}\nfunction verify2FA(){var code=$('verify2FACode').value.trim();if(code.length!==6){alert('请输入6位验证码');return}api('/api/auth/2fa/verify',{method:'POST',body:JSON.stringify({code:code})}).then(function(data){closeModal('2faModal');$('2faStatus').textContent='已启用';$('2faStatus').style.color='var(--success)';$('2faBtn').textContent='禁用';$('2faBtn').onclick=disable2FA;showToast('2FA 已启用')}).catch(function(e){alert('验证失败: '+e.message)})}\nfunction disable2FA(){var code=prompt('输入6位验证码以禁用 2FA:');if(!code)return;api('/api/auth/2fa/disable',{method:'POST',body:JSON.stringify({code:code})}).then(function(){$('2faStatus').textContent='未启用';$('2faStatus').style.color='var(--text2)';$('2faBtn').textContent='设置';$('2faBtn').onclick=setup2FA;showToast('2FA 已禁用')}).catch(function(e){alert('禁用失败: '+e.message)})}\nfunction showChangePasswordModal(){var html='<div class=\"form-group\"><label>当前密码</label><input type=\"password\" id=\"oldPassword\"></div><div class=\"form-group\"><label>新密码</label><input type=\"password\" id=\"newPassword\"></div><div class=\"form-group\"><label>确认新密码</label><input type=\"password\" id=\"confirmPassword\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"changePassword()\">修改</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pwdModal\\')\">取消</button></div>';showCustomModal('修改密码',html,'pwdModal')}\nfunction changePassword(){var oldPwd=$('oldPassword').value,newPwd=$('newPassword').value,confirmPwd=$('confirmPassword').value;if(!oldPwd||!newPwd){alert('请填写密码');return}if(newPwd!==confirmPwd){alert('两次密码不一致');return}alert('密码修改功能开发中')}\n// 检查 URL 中的 token(OAuth 回调)\n(function(){var params=new URLSearchParams(window.location.search);var token=params.get('token');if(token){localStorage.setItem('token',token);authToken=token;window.history.replaceState({},document.title,'/');checkAuth()}})();\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\n// 代码运行器\nfunction runCode(){var code=$('codeInput').value;var lang=$('codeLanguage').value;if(!code.trim()){alert('请输入代码');return}$('codeOutput').textContent='运行中...';$('codeOutput').style.color='var(--text2)';api('/api/code/run',{method:'POST',body:JSON.stringify({code:code,language:lang,timeout:5})}).then(function(data){if(data.success){$('codeOutput').textContent=data.output||'(无输出)';$('codeOutput').style.color='var(--success)'}else{$('codeOutput').textContent='错误: '+(data.error||'未知错误')+'\\n'+data.output;$('codeOutput').style.color='var(--error)'}}).catch(function(e){$('codeOutput').textContent='请求失败: '+e.message;$('codeOutput').style.color='var(--error)'})}\n// 思维导图\nfunction generateMindmap(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}showToast('正在生成思维导图...');api('/api/mindmap/generate',{method:'POST',body:JSON.stringify({messages:chat.messages,title:chat.title})}).then(function(data){renderMindmap(data.nodes)}).catch(function(e){alert('生成失败: '+e.message)})}\nfunction renderMindmap(nodes){var html='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.8);z-index:2000;display:flex;align-items:center;justify-content:center\" onclick=\"if(event.target===this)this.remove()\"><div style=\"background:var(--bg2);border-radius:16px;padding:24px;max-width:800px;max-height:80vh;overflow:auto\"><h3 style=\"margin-bottom:16px\">🧠 思维导图</h3><div id=\"mindmapContent\" style=\"padding:20px\"></div><button class=\"btn btn-ghost\" onclick=\"this.parentElement.parentElement.remove()\">关闭</button></div></div>';document.body.insertAdjacentHTML('beforeend',html);var content='';function renderNode(node,level){var indent=level*24;content+='<div style=\"margin-left:'+indent+'px;padding:8px 12px;margin-bottom:4px;background:var(--bg'+(level>0?'3':'')+');border-radius:6px;border-left:3px solid var(--accent)\">'+(level>0?'├─ ':'')+node.label+'</div>';if(node.children){node.children.forEach(function(c){renderNode(c,level+1)})}}if(nodes&&nodes.length)renderNode(nodes[0],0);$('mindmapContent').innerHTML=content||'<p style=\"color:var(--text2)\">无法生成思维导图</p>'}\n// 保存对话为模板\nfunction saveAsTemplate(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}var name=prompt('模板名称:',chat.title);if(!name)return;api('/api/chat-templates',{method:'POST',body:JSON.stringify({name:name,messages:chat.messages})}).then(function(){showToast('已保存为模板')}).catch(function(e){alert('保存失败: '+e.message)})}\n// 用量配额\nfunction loadQuota(){api('/api/quota').then(function(data){var html='<div style=\"margin-bottom:16px\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Token 使用量</span><span>'+formatNumber(data.tokens_used)+' / '+formatNumber(data.tokens_limit)+'</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;overflow:hidden\"><div style=\"background:var(--accent);height:100%;width:'+data.usage_percent+'%\"></div></div></div><p style=\"font-size:12px;color:var(--text2)\">当前套餐: '+data.plan+'</p>';if($('quotaInfo'))$('quotaInfo').innerHTML=html}).catch(function(e){console.error(e)})}\n// PWA 注册\nif('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js').then(function(reg){console.log('SW registered');if('Notification' in window&&Notification.permission==='default'){Notification.requestPermission()}}).catch(function(e){console.error('SW failed:',e)})}\n// 图片生成\nfunction generateImage(){var prompt=prompt('输入图片描述:');if(!prompt)return;showToast('正在生成图片...');api('/api/images/generate',{method:'POST',body:JSON.stringify({prompt:prompt})}).then(function(data){var img='<img src=\"'+data.url+'\" style=\"max-width:100%;border-radius:8px\">';var chat=chats.find(function(c){return c.id===currentChatId});if(chat){chat.messages.push({role:'assistant',content:'![生成的图片]('+data.url+')\\n\\n'+data.revised_prompt});saveChats();renderMessages()}showToast('图片已生成')}).catch(function(e){alert('生成失败: '+e.message)})}\n// TTS 语音合成\nfunction speakText(text){api('/api/audio/tts',{method:'POST',body:JSON.stringify({text:text,voice:'alloy'})}).then(function(data){var audio=new Audio(data.audio);audio.play();showToast('正在播放')}).catch(function(e){if('speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(text);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('TTS 失败: '+e.message)}})}\n// 内容过滤\nfunction filterContent(text){return api('/api/content/filter',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data})}\n// 数据脱敏\nfunction maskData(text){return api('/api/data/mask',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data.masked})}\n// 备份\nfunction createBackup(){api('/api/backup',{method:'POST'}).then(function(data){showToast('备份已创建: '+data.path)}).catch(function(e){alert('备份失败: '+e.message)})}\n// 离线检测\nwindow.addEventListener('online',function(){showToast('网络已恢复')});\nwindow.addEventListener('offline',function(){showToast('网络已断开,部分功能不可用')});\n\n// ========== 性能监控面板 ==========\nfunction showHealthDashboard(){\napi('/api/health/detailed').then(function(data){\nvar html='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">CPU 使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.cpu_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.cpu_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">内存使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.memory_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.memory_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">磁盘使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.disk_percent>90?'var(--error)':'var(--success)')+'\">'+data.system.disk_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">数据库延迟</div><div style=\"font-size:24px;font-weight:600;color:'+(data.components.database.latency_ms>100?'var(--warning)':'var(--success)')+'\">'+data.components.database.latency_ms+'ms</div></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:10px\">';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>缓存</span><span>'+data.components.cache.size+'/'+data.components.cache.max_size+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Redis</span><span style=\"color:'+(data.components.redis.status==='healthy'?'var(--success)':'var(--warning)')+'\">'+data.components.redis.status+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between\"><span>待处理任务</span><span>'+data.components.task_queue.pending_tasks+'</span></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;text-align:center;font-size:12px;color:var(--text2)\">版本 '+data.version+' · 运行时间 '+formatUptime(data.uptime_seconds)+'</div>';\nshowCustomModal('🖥️ 系统状态',html,'healthModal')\n}).catch(function(e){alert('获取状态失败: '+e.message)})}\nfunction formatUptime(seconds){var h=Math.floor(seconds/3600);var m=Math.floor((seconds%3600)/60);return h+'小时'+m+'分钟'}\n\n// ========== 批量操作 ==========\nvar batchMode=false;\nvar selectedChats=[];\nfunction toggleBatchMode(){batchMode=!batchMode;selectedChats=[];if(batchMode){$('batchActions').style.display='flex';showToast('已进入批量选择模式')}else{$('batchActions').style.display='none'}renderChatList()}\nfunction toggleChatSelection(id,e){if(!batchMode)return;e.stopPropagation();var idx=selectedChats.indexOf(id);if(idx>=0){selectedChats.splice(idx,1)}else{selectedChats.push(id)}renderChatList();$('selectedCount').textContent=selectedChats.length}\nfunction batchDeleteChats(){if(selectedChats.length===0){alert('请先选择对话');return}if(!confirm('确定删除 '+selectedChats.length+' 个对话?'))return;api('/api/conversations/batch-delete',{method:'POST',body:JSON.stringify({ids:selectedChats})}).then(function(data){showToast('已删除 '+data.deleted+' 个对话');selectedChats=[];batchMode=false;$('batchActions').style.display='none';loadChats()}).catch(function(e){alert('删除失败: '+e.message)})}\nfunction batchExportChats(){if(selectedChats.length===0){alert('请先选择对话');return}api('/api/messages/batch-export',{method:'POST',body:JSON.stringify({conversation_ids:selectedChats,format:'json'})}).then(function(data){var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='conversations_export.json';a.click();showToast('已导出 '+data.count+' 个对话')}).catch(function(e){alert('导出失败: '+e.message)})}\n\n// ========== 数据库优化 ==========\nfunction optimizeDatabase(){if(!confirm('确定要优化数据库?这将清理过期数据。'))return;showToast('正在优化...');api('/api/admin/optimize-db',{method:'POST'}).then(function(data){showToast(data.message)}).catch(function(e){alert('优化失败: '+e.message)})}\n\n// ========== 快捷键增强 ==========\ndocument.addEventListener('keydown',function(e){\nif(e.ctrlKey&&e.key==='h'){e.preventDefault();showHealthDashboard()}\nif(e.ctrlKey&&e.key==='b'){e.preventDefault();toggleBatchMode()}\nif(e.ctrlKey&&e.shiftKey&&e.key==='E'){e.preventDefault();batchExportChats()}\nif(e.ctrlKey&&e.key==='f'){e.preventDefault();searchInCurrentChat()}\nif(e.ctrlKey&&e.key==='/'||e.key==='?'){e.preventDefault();showHotkeyHelp()}\n});\n\n// ========== 性能优化:虚拟滚动 ==========\nfunction renderChatListVirtual(){\nvar container=$('chatList');\nvar itemHeight=60;\nvar visibleCount=Math.ceil(container.clientHeight/itemHeight)+2;\nvar scrollTop=container.scrollTop;\nvar startIndex=Math.floor(scrollTop/itemHeight);\nvar endIndex=Math.min(startIndex+visibleCount,chats.length);\nvar html='<div style=\"height:'+(startIndex*itemHeight)+'px\"></div>';\nfor(var i=startIndex;i<endIndex;i++){\nvar c=chats[i];\nvar active=c.id===currentChatId?'active':'';\nvar selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';\nvar checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';\nhtml+='<div class=\"sidebar-item '+active+'\" style=\"'+selected+'\" onclick=\"loadChat(\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+c.title+'</div><div class=\"sidebar-item-desc\">'+(c.messages.length||0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" style=\"opacity:0\" onclick=\"deleteChat(\\''+c.id+'\\',event)\">🗑️</button></div>'\n}\nhtml+='<div style=\"height:'+((chats.length-endIndex)*itemHeight)+'px\"></div>';\ncontainer.innerHTML=html}\n\n// ========== 请求重试机制 ==========\nasync function apiWithRetry(url,options,maxRetries=3){\nfor(var i=0;i<maxRetries;i++){\ntry{return await api(url,options)}\ncatch(e){\nif(i===maxRetries-1)throw e;\nawait new Promise(function(r){setTimeout(r,1000*(i+1))});\nconsole.log('Retrying request...',i+1)\n}}}\n\n// ========== 消息队列(离线支持) ==========\nvar offlineQueue=JSON.parse(localStorage.getItem('offlineQueue')||'[]');\nfunction queueOfflineMessage(msg){offlineQueue.push({msg:msg,time:Date.now()});localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))}\nfunction processOfflineQueue(){if(offlineQueue.length===0)return;showToast('正在发送离线消息...');var msg=offlineQueue.shift();localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue));sendMessageInternal(msg.msg).then(function(){processOfflineQueue()}).catch(function(){offlineQueue.unshift(msg);localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))})}\nwindow.addEventListener('online',processOfflineQueue);\n\n// ========== 智能预加载 ==========\nfunction preloadNextChat(){\nvar currentIdx=chats.findIndex(function(c){return c.id===currentChatId});\nif(currentIdx>=0&&currentIdx<chats.length-1){\nvar nextChat=chats[currentIdx+1];\nif(!nextChat.messages||nextChat.messages.length===0){\napi('/api/conversations/'+nextChat.id+'/messages').then(function(msgs){nextChat.messages=msgs})}}}\n\n// ========== 自动保存草稿 ==========\nvar draftTimer=null;\nfunction saveDraft(){var input=$('chatInput').value;if(input&&currentChatId){localStorage.setItem('draft_'+currentChatId,input)}}\nfunction loadDraft(){if(currentChatId){var draft=localStorage.getItem('draft_'+currentChatId);if(draft)$('chatInput').value=draft}}\nfunction clearDraft(){if(currentChatId)localStorage.removeItem('draft_'+currentChatId)}\n$('chatInput').addEventListener('input',function(){clearTimeout(draftTimer);draftTimer=setTimeout(saveDraft,1000)});\n\n// ========== 消息搜索增强 ==========\nfunction searchInCurrentChat(){var q=prompt('在当前对话中搜索:');if(!q)return;var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages)return;var results=chat.messages.filter(function(m){return m.content&&m.content.toLowerCase().includes(q.toLowerCase())});if(results.length===0){alert('未找到匹配消息');return}var html='<div style=\"max-height:400px;overflow-y:auto\">';results.forEach(function(m,i){html+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:4px\">'+(m.role==='user'?'👤 用户':'🤖 助手')+'</div><div style=\"font-size:14px\">'+m.content.slice(0,200)+(m.content.length>200?'...':'')+'</div></div>'});html+='</div>';showCustomModal('搜索结果 ('+results.length+')',html,'searchResultModal')}\n\n// ========== 快速回复 ==========\nvar quickReplies=[\n{id:'continue',text:'继续',prompt:'请继续'},\n{id:'explain',text:'解释',prompt:'请详细解释一下'},\n{id:'example',text:'举例',prompt:'请举个例子'},\n{id:'simplify',text:'简化',prompt:'请用更简单的语言解释'},\n{id:'code',text:'代码',prompt:'请给出代码示例'},\n{id:'summary',text:'总结',prompt:'请总结一下要点'}\n];\nfunction showQuickReplies(){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages||chat.messages.length===0){$('quickReplies').style.display='none';return}\nvar lastMsg=chat.messages[chat.messages.length-1];\nif(lastMsg.role!=='assistant'){$('quickReplies').style.display='none';return}\nvar html=quickReplies.map(function(r){return'<button class=\"btn btn-ghost btn-sm\" onclick=\"sendQuickReply(\\''+r.prompt+'\\')\">'+r.text+'</button>'}).join('');\n$('quickReplies').innerHTML=html;\n$('quickReplies').style.display='flex'}\nfunction sendQuickReply(prompt){$('chatInput').value=prompt;sendMessage()}\n\n// ========== 数据导入导出 ==========\nfunction exportAllData(){\nif(!authToken){alert('请先登录');return}\nshowToast('正在导出数据...');\napi('/api/data/export-all',{method:'POST'}).then(function(data){\nvar blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='ai_hub_backup_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})}\n\nfunction importAllData(){\nif(!authToken){alert('请先登录');return}\nvar input=document.createElement('input');\ninput.type='file';\ninput.accept='.json';\ninput.onchange=function(e){\nvar file=e.target.files[0];\nif(!file)return;\nvar reader=new FileReader();\nreader.onload=function(ev){\ntry{\nvar data=JSON.parse(ev.target.result);\nif(!confirm('确定要导入数据?这将添加 '+\n(data.conversations?data.conversations.length:0)+' 个对话、'+\n(data.notes?data.notes.length:0)+' 个笔记'))return;\napi('/api/data/import',{method:'POST',body:JSON.stringify(data)}).then(function(result){\nshowToast('导入完成: '+result.imported.conversations+' 对话, '+result.imported.notes+' 笔记');\nloadChats()\n}).catch(function(e){alert('导入失败: '+e.message)})\n}catch(e){alert('文件格式错误')}};\nreader.readAsText(file)};\ninput.click()}\n\n// ========== 智能推荐 ==========\nfunction loadRecommendations(){\napi('/api/recommendations').then(function(data){\nif(data.features&&data.features.length>0){\nvar html='<div style=\"padding:16px;background:var(--bg3);border-radius:10px;margin-bottom:16px\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:12px\">💡 推荐功能</div><div style=\"display:flex;gap:12px;flex-wrap:wrap\">';\ndata.features.forEach(function(f){\nhtml+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;cursor:pointer;flex:1;min-width:150px\" onclick=\"showFeatureGuide(\\''+f.name+'\\')\"><span style=\"font-size:20px\">'+f.icon+'</span><div style=\"font-size:14px;font-weight:500;margin-top:8px\">'+f.name+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+f.desc+'</div></div>'});\nhtml+='</div></div>';\nvar container=$('chatMessages');\nif(container&&container.querySelector('.empty-state')){\ncontainer.innerHTML=html+container.innerHTML}}\n}).catch(function(){})}\nfunction showFeatureGuide(name){\nvar guides={\n'知识库':'点击左侧导航的\"知识库\",创建知识库并上传文档,AI 将基于您的资料回答问题。',\n'团队协作':'点击左侧导航的\"团队空间\",创建团队并邀请成员,共享对话和资源。'\n};\nalert(guides[name]||'功能介绍开发中')}\n\n// ========== 收藏消息 ==========\nfunction favoriteMessage(content){\nif(!authToken){alert('请先登录');return}\napi('/api/messages/favorite',{method:'POST',body:JSON.stringify({\nconversation_id:currentChatId,\ncontent:content\n})}).then(function(){showToast('已收藏到记忆')}).catch(function(e){alert('收藏失败: '+e.message)})}\nfunction favoriteMessageByIndex(index){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages[index])return;\nfavoriteMessage(chat.messages[index].content)}\n\n// ========== 使用分析 ==========\nfunction showUsageAnalytics(){\napi('/api/analytics/usage?days=30').then(function(data){\nvar html='<div style=\"margin-bottom:20px\"><h4 style=\"margin-bottom:12px\">📊 30天使用趋势</h4>';\nif(data.daily_usage.length>0){\nvar maxCalls=Math.max.apply(null,data.daily_usage.map(function(d){return d.calls}));\nhtml+='<div style=\"display:flex;align-items:flex-end;gap:4px;height:100px\">';\ndata.daily_usage.forEach(function(d){\nvar height=Math.max(5,(d.calls/maxCalls)*100);\nhtml+='<div style=\"flex:1;background:var(--accent);border-radius:2px 2px 0 0;height:'+height+'px\" title=\"'+d.day+': '+d.calls+'次\"></div>'});\nhtml+='</div>'}\nhtml+='</div>';\nhtml+='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">总调用次数</div><div style=\"font-size:24px;font-weight:600\">'+data.total_calls+'</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">错误率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.error_rate>5?'var(--error)':'var(--success)')+'\">'+data.error_rate+'%</div></div>';\nhtml+='</div>';\nshowCustomModal('📈 使用分析',html,'analyticsModal')\n}).catch(function(e){alert('获取分析失败: '+e.message)})}\n\n// ========== 第三方集成 ==========\nfunction saveIntegration(type){\nvar data={};\nif(type==='slack'){\ndata={slack_token:$('slackToken').value,slack_secret:$('slackSecret').value}\n}else if(type==='feishu'){\ndata={feishu_app_id:$('feishuAppId').value,feishu_secret:$('feishuSecret').value}\n}else if(type==='webhook'){\ndata={webhook_url:$('webhookUrl').value,webhook_new_msg:$('webhookNewMsg').checked,webhook_error:$('webhookError').checked}\n}\nlocalStorage.setItem('integration_'+type,JSON.stringify(data));\nshowToast('配置已保存')}\n\nfunction loadIntegrations(){\ntry{\nvar slack=JSON.parse(localStorage.getItem('integration_slack')||'{}');\nif(slack.slack_token)$('slackToken').value=slack.slack_token;\nif(slack.slack_secret)$('slackSecret').value=slack.slack_secret;\nvar feishu=JSON.parse(localStorage.getItem('integration_feishu')||'{}');\nif(feishu.feishu_app_id)$('feishuAppId').value=feishu.feishu_app_id;\nif(feishu.feishu_secret)$('feishuSecret').value=feishu.feishu_secret;\nvar webhook=JSON.parse(localStorage.getItem('integration_webhook')||'{}');\nif(webhook.webhook_url)$('webhookUrl').value=webhook.webhook_url;\nif(webhook.webhook_new_msg)$('webhookNewMsg').checked=true;\nif(webhook.webhook_error)$('webhookError').checked=true;\n}catch(e){}}\n\nfunction testSlackIntegration(){\nshowToast('测试 Slack 连接...');\napi('/api/integrations/slack/send',{method:'POST',body:JSON.stringify({channel:'#general',text:'AI Hub 测试消息'})}).then(function(data){\nif(data.ok){showToast('Slack 连接成功!')}else{alert('连接失败: '+(data.error||'未知错误'))}\n}).catch(function(e){alert('连接失败: '+e.message)})}\n\nfunction testFeishuIntegration(){\nshowToast('测试飞书连接...');\napi('/api/integrations/feishu/send',{method:'POST',body:JSON.stringify({chat_id:'test',text:'AI Hub 测试消息'})}).then(function(data){\nif(data.code===0){showToast('飞书连接成功!')}else{alert('连接失败: '+(data.msg||'未知错误'))}\n}).catch(function(e){alert('连接失败: '+e.message)})}\n\n// ========== 灰度发布 ==========\nfunction loadFeatureFlags(){\napi('/api/features/all').then(function(data){\nvar html='';\nfor(var name in data){\nvar flag=data[name];\nhtml+='<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\">';\nhtml+='<div><strong>'+name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">灰度比例: '+flag.percentage+'% · 白名单用户: '+(flag.users?flag.users.length:0)+'</div></div>';\nhtml+='<label class=\"switch\"><input type=\"checkbox\" '+(flag.enabled?'checked':'')+' onchange=\"toggleFeatureFlag(\\''+name+'\\',this.checked)\"><span class=\"switch-slider\"></span></label>';\nhtml+='</div>'}\n$('featureFlagsList').innerHTML=html||'<p style=\"color:var(--text2)\">暂无功能开关</p>'\n}).catch(function(e){$('featureFlagsList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction toggleFeatureFlag(name,enabled){\napi('/api/features/'+name,{method:'POST',body:JSON.stringify({enabled:enabled})}).then(function(){\nshowToast(name+(enabled?' 已启用':' 已禁用'))\n}).catch(function(e){alert('操作失败: '+e.message)})}\n\nfunction updateFeatureFlagPercentage(name,percentage){\napi('/api/features/'+name,{method:'POST',body:JSON.stringify({percentage:parseInt(percentage)})}).then(function(){\nshowToast('灰度比例已更新')\n}).catch(function(e){alert('操作失败: '+e.message)})}\n\n// ========== 链路追踪 ==========\nfunction loadTraces(){\napi('/api/traces?limit=50').then(function(data){\nif(data.length===0){$('tracesList').innerHTML='<p style=\"color:var(--text2)\">暂无追踪记录</p>';return}\nvar html='<table style=\"width:100%;border-collapse:collapse;font-size:13px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">ID</th><th style=\"padding:10px\">名称</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">Spans</th></tr>';\ndata.forEach(function(t){\nhtml+='<tr style=\"border-top:1px solid var(--border);cursor:pointer\" onclick=\"showTraceDetail(\\''+t.id+'\\')\">';\nhtml+='<td style=\"padding:10px;font-family:monospace\">'+t.id+'</td>';\nhtml+='<td style=\"padding:10px\">'+t.name+'</td>';\nhtml+='<td style=\"padding:10px;text-align:right\">'+(t.total_duration?(t.total_duration*1000).toFixed(0)+'ms':'-')+'</td>';\nhtml+='<td style=\"padding:10px\">'+(t.spans?t.spans.length:0)+'</td>';\nhtml+='</tr>'});\nhtml+='</table>';\n$('tracesList').innerHTML=html\n}).catch(function(e){$('tracesList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction showTraceDetail(traceId){\napi('/api/traces/'+traceId).then(function(data){\nvar html='<div style=\"margin-bottom:16px\"><strong>Trace ID:</strong> '+data.id+'<br><strong>名称:</strong> '+data.name+'<br><strong>总耗时:</strong> '+(data.total_duration?(data.total_duration*1000).toFixed(0)+'ms':'-')+'</div>';\nif(data.spans&&data.spans.length>0){\nhtml+='<h4 style=\"margin-bottom:12px\">Spans</h4>';\ndata.spans.forEach(function(s,i){\nvar width=Math.min(100,s.duration*100);\nhtml+='<div style=\"margin-bottom:8px\"><div style=\"display:flex;justify-content:space-between;font-size:13px\"><span>'+s.name+'</span><span>'+(s.duration*1000).toFixed(0)+'ms</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;margin-top:4px\"><div style=\"background:var(--accent);height:100%;width:'+width+'%;border-radius:4px\"></div></div></div>'\n})}\nshowCustomModal('🔍 追踪详情',html,'traceDetailModal')\n}).catch(function(e){alert('加载失败: '+e.message)})}\n\nfunction exportTraces(){\napi('/api/traces?limit=100').then(function(data){\nif(data.length===0){alert('暂无追踪记录');return}\nvar traceIds=data.map(function(t){return t.id});\napi('/api/traces/export',{method:'POST',body:JSON.stringify({trace_ids:traceIds,format:'jaeger'})}).then(function(result){\nvar blob=new Blob([JSON.stringify(result.data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='traces_export_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('追踪数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})\n}).catch(function(e){alert('获取追踪失败: '+e.message)})}\n\n// ========== 多 Agent 协作 ==========\nfunction loadAgents(){\napi('/api/agents').then(function(data){\nvar html=data.map(function(a){\nreturn'<label style=\"display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer\"><input type=\"checkbox\" class=\"agent-checkbox\" value=\"'+a.name+'\" checked><span>'+a.name+'</span><span style=\"font-size:11px;color:var(--text2)\">'+a.role+'</span></label>'\n}).join('');\n$('agentCheckboxes').innerHTML=html\n}).catch(function(){})}\n\nfunction runMultiAgent(){\nvar task=$('multiAgentTask').value.trim();\nif(!task){alert('请输入任务描述');return}\nvar agents=[];\ndocument.querySelectorAll('.agent-checkbox:checked').forEach(function(cb){agents.push(cb.value)});\nif(agents.length<2){alert('请至少选择2个Agent');return}\nvar mode=$('agentMode').value;\n$('multiAgentResults').style.display='block';\n$('multiAgentResultsContent').innerHTML='<p style=\"color:var(--text2)\">Agent 正在协作中...</p>';\napi('/api/agents/collaborate',{method:'POST',body:JSON.stringify({task:task,agents:agents,mode:mode})}).then(function(data){\nvar html='<div style=\"font-size:12px;color:var(--text2);margin-bottom:16px\">模式: '+data.mode+'</div>';\nfor(var name in data.results){\nhtml+='<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px;border-left:4px solid var(--accent)\"><div style=\"font-weight:500;margin-bottom:8px\">'+name+'</div><div style=\"font-size:14px;line-height:1.6\">'+marked.parse(data.results[name])+'</div></div>'\n}\n$('multiAgentResultsContent').innerHTML=html\n}).catch(function(e){$('multiAgentResultsContent').innerHTML='<p style=\"color:var(--error)\">执行失败: '+e.message+'</p>'})}\n\nfunction showCreateAgentModal(){\nvar html='<div class=\"form-group\"><label>Agent 名称</label><input type=\"text\" id=\"newAgentName\" placeholder=\"分析师\"></div><div class=\"form-group\"><label>角色描述</label><input type=\"text\" id=\"newAgentRole\" placeholder=\"数据分析专家\"></div><div class=\"form-group\"><label>使用模型</label><input type=\"text\" id=\"newAgentModel\" value=\"gpt-4o-mini\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createAgent()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'agentModal\\')\">取消</button></div>';\nshowCustomModal('创建 Agent',html,'agentModal')}\n\nfunction createAgent(){\nvar name=$('newAgentName').value.trim();\nvar role=$('newAgentRole').value.trim();\nvar model=$('newAgentModel').value.trim()||'gpt-4o-mini';\nif(!name||!role){alert('请填写名称和角色');return}\napi('/api/agents/create',{method:'POST',body:JSON.stringify({name:name,role:role,model:model})}).then(function(){\ncloseModal('agentModal');\nloadAgents();\nshowToast('Agent 已创建')\n}).catch(function(e){alert('创建失败: '+e.message)})}\n\n// ========== 本地模型 (Ollama) ==========\nfunction loadOllamaModels(){\n$('ollamaStatus').innerHTML='<span style=\"color:var(--text2)\">检查 Ollama 连接...</span>';\napi('/api/ollama/models').then(function(data){\nif(data.error){\n$('ollamaStatus').innerHTML='<span style=\"color:var(--error)\">❌ '+data.error+'</span>';\n$('ollamaModelList').innerHTML='';\n$('ollamaModelSelect').innerHTML='<option>无可用模型</option>';\nreturn}\n$('ollamaStatus').innerHTML='<span style=\"color:var(--success)\">✅ Ollama 已连接,共 '+data.models.length+' 个模型</span>';\nvar html=data.models.map(function(m){\nvar size=(m.size/1024/1024/1024).toFixed(1);\nreturn'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div><strong>'+m.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+size+' GB</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"selectOllamaModel(\\''+m.name+'\\')\">使用</button></div>'\n}).join('');\n$('ollamaModelList').innerHTML=html||'<p style=\"color:var(--text2)\">暂无模型,请先拉取</p>';\nvar selectHtml=data.models.map(function(m){return'<option value=\"'+m.name+'\">'+m.name+'</option>'}).join('');\n$('ollamaModelSelect').innerHTML=selectHtml||'<option>无可用模型</option>'\n}).catch(function(e){$('ollamaStatus').innerHTML='<span style=\"color:var(--error)\">❌ 连接失败</span>'})}\n\nfunction showPullModelModal(){\nvar html='<div class=\"form-group\"><label>模型名称</label><input type=\"text\" id=\"pullModelName\" placeholder=\"llama2, mistral, codellama...\"></div><p style=\"font-size:12px;color:var(--text2);margin-bottom:16px\">常用模型: llama2, mistral, codellama, phi, gemma</p><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"pullOllamaModel()\">拉取</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pullModal\\')\">取消</button></div>';\nshowCustomModal('拉取 Ollama 模型',html,'pullModal')}\n\nfunction pullOllamaModel(){\nvar model=$('pullModelName').value.trim();\nif(!model){alert('请输入模型名称');return}\nshowToast('开始拉取 '+model+',请稍候...');\ncloseModal('pullModal');\napi('/api/ollama/pull',{method:'POST',body:JSON.stringify({model:model})}).then(function(data){\nif(data.success){showToast('模型拉取成功!');loadOllamaModels()}else{alert('拉取失败')}\n}).catch(function(e){alert('拉取失败: '+e.message)})}\n\nfunction selectOllamaModel(name){$('ollamaModelSelect').value=name;showToast('已选择 '+name)}\n\nfunction chatWithOllama(){\nvar model=$('ollamaModelSelect').value;\nvar message=$('ollamaMessage').value.trim();\nif(!model||!message){alert('请选择模型并输入消息');return}\n$('ollamaResponse').style.display='block';\n$('ollamaResponse').innerHTML='<p style=\"color:var(--text2)\">思考中...</p>';\napi('/api/ollama/chat',{method:'POST',body:JSON.stringify({model:model,messages:[{role:'user',content:message}]})}).then(function(data){\nvar content=data.message?data.message.content:'无响应';\n$('ollamaResponse').innerHTML=marked.parse(content)\n}).catch(function(e){$('ollamaResponse').innerHTML='<p style=\"color:var(--error)\">错误: '+e.message+'</p>'})}\n\nfunction loadVLLMModels(){\nvar url=$('vllmUrl').value.trim();\n$('vllmStatus').innerHTML='<span style=\"color:var(--text2)\">检查连接...</span>';\nfetch(url+'/v1/models').then(function(r){return r.json()}).then(function(data){\nif(data.data&&data.data.length>0){\n$('vllmStatus').innerHTML='<span style=\"color:var(--success)\">✅ vLLM 已连接,模型: '+data.data.map(function(m){return m.id}).join(', ')+'</span>'\n}else{\n$('vllmStatus').innerHTML='<span style=\"color:var(--warning)\">⚠️ 已连接但无模型</span>'\n}\n}).catch(function(){$('vllmStatus').innerHTML='<span style=\"color:var(--error)\">❌ 无法连接到 vLLM</span>'})}\n\n// ========== RAG 检索 ==========\nfunction loadRAGKnowledgeBases(){\napi('/api/knowledge-bases').then(function(data){\nvar html='<option value=\"\">选择知识库</option>';\ndata.forEach(function(kb){html+='<option value=\"'+kb.id+'\">'+kb.name+'</option>'});\n$('ragKbSelect').innerHTML=html\n}).catch(function(){})}\n\nfunction searchRAG(){\nvar kbId=$('ragKbSelect').value;\nvar query=$('ragQuery').value.trim();\nif(!kbId){alert('请选择知识库');return}\nif(!query){alert('请输入问题');return}\n$('ragResults').innerHTML='<p style=\"color:var(--text2)\">搜索中...</p>';\napi('/api/rag/search',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),query:query,top_k:5})}).then(function(data){\nif(data.results.length===0){$('ragResults').innerHTML='<p style=\"color:var(--text2)\">未找到相关内容</p>';return}\nvar html=data.results.map(function(r,i){\nreturn'<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px;border-left:4px solid var(--accent)\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span style=\"font-weight:500\">#'+(i+1)+' '+r.chunk_id+'</span><span style=\"color:var(--accent)\">相似度: '+(r.score*100).toFixed(1)+'%</span></div><div style=\"font-size:14px;color:var(--text2);line-height:1.6\">'+r.content.slice(0,300)+(r.content.length>300?'...':'')+'</div></div>'\n}).join('');\n$('ragResults').innerHTML=html\n}).catch(function(e){$('ragResults').innerHTML='<p style=\"color:var(--error)\">搜索失败: '+e.message+'</p>'})}\n\nfunction chatWithRAG(){\nvar kbId=$('ragKbSelect').value;\nvar query=$('ragQuery').value.trim();\nif(!kbId){alert('请选择知识库');return}\nif(!query){alert('请输入问题');return}\n$('ragResults').innerHTML='<p style=\"color:var(--text2)\">AI 正在思考...</p>';\napi('/api/rag/chat',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),question:query})}).then(function(data){\nvar html='<div style=\"padding:20px;background:var(--bg);border-radius:12px\"><div style=\"font-size:14px;line-height:1.8\">'+marked.parse(data.answer)+'</div>';\nif(data.sources&&data.sources.length>0){\nhtml+='<div style=\"margin-top:16px;padding-top:16px;border-top:1px solid var(--border)\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:8px\">参考来源:</div>';\ndata.sources.forEach(function(s){html+='<span class=\"tag\" style=\"margin-right:8px\">'+s.chunk_id+' ('+(s.score*100).toFixed(0)+'%)</span>'});\nhtml+='</div>'}\nhtml+='</div>';\n$('ragResults').innerHTML=html\n}).catch(function(e){$('ragResults').innerHTML='<p style=\"color:var(--error)\">对话失败: '+e.message+'</p>'})}\n\nfunction indexDocument(){\nvar kbId=$('ragKbSelect').value;\nvar content=$('ragContent').value.trim();\nvar filename=$('ragFilename').value.trim()||'document.txt';\nif(!kbId){alert('请选择知识库');return}\nif(!content){alert('请输入文档内容');return}\nshowToast('正在索引文档...');\napi('/api/rag/index',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),content:content,filename:filename})}).then(function(data){\nshowToast('索引完成,共 '+data.indexed_chunks+' 个分块');\n$('ragContent').value='';\n$('ragFilename').value=''\n}).catch(function(e){alert('索引失败: '+e.message)})}\n\n// ========== 计费系统 ==========\nfunction loadBillingPlans(){\napi('/api/billing/plans').then(function(data){\nvar html=data.map(function(p){\nvar features=JSON.parse(p.features||'[]');\nreturn'<div class=\"price-card\" onclick=\"subscribePlan(\\''+p.id+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">¥'+p.price+'<span>/月</span></div><ul>'+features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn btn-primary\" style=\"width:100%\">选择</button></div>'\n}).join('');\n$('billingPlans').innerHTML=html\n}).catch(function(){})}\n\nfunction loadSubscription(){\napi('/api/billing/subscription').then(function(data){\n$('currentPlanName').textContent=data.plan_name||data.plan||'免费版';\nvar remaining=data.tokens_limit===-1?'无限':formatNumber(data.tokens_limit||10000);\n$('remainingQuota').textContent=remaining\n}).catch(function(){})}\n\nfunction loadUsageStats(){\napi('/api/billing/usage?period=month').then(function(data){\nvar html='';\nfor(var type in data.usage){\nvar u=data.usage[type];\nhtml+='<div style=\"padding:16px;background:var(--bg);border-radius:10px;text-align:center\"><div style=\"font-size:24px;font-weight:600;color:var(--accent)\">'+formatNumber(u.amount)+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+type+'</div><div style=\"font-size:11px;color:var(--success);margin-top:4px\">¥'+u.cost.toFixed(2)+'</div></div>'\n}\n$('usageStats').innerHTML=html||'<p style=\"color:var(--text2);grid-column:1/-1;text-align:center\">暂无用量数据</p>'\n}).catch(function(){})}\n\nfunction loadInvoices(){\napi('/api/billing/invoices').then(function(data){\nif(data.length===0){$('invoiceList').innerHTML='<p style=\"color:var(--text2)\">暂无发票</p>';return}\nvar html=data.map(function(inv){\nvar statusColor=inv.status==='paid'?'var(--success)':'var(--warning)';\nreturn'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div><div style=\"font-weight:500\">'+inv.id+'</div><div style=\"font-size:12px;color:var(--text2)\">'+(inv.created_at||'').slice(0,10)+'</div></div><div style=\"text-align:right\"><div style=\"font-weight:600\">¥'+inv.amount+'</div><div style=\"font-size:12px;color:'+statusColor+'\">'+(inv.status==='paid'?'已支付':'待支付')+'</div></div>'+(inv.status!=='paid'?'<button class=\"btn btn-primary btn-sm\" onclick=\"payInvoice(\\''+inv.id+'\\')\">支付</button>':'')+'</div>'\n}).join('');\n$('invoiceList').innerHTML=html\n}).catch(function(){})}\n\nfunction subscribePlan(planId){\nif(!authToken){alert('请先登录');return}\nif(!confirm('确定订阅此套餐?'))return;\napi('/api/billing/subscribe',{method:'POST',body:JSON.stringify({plan_id:planId,months:1})}).then(function(data){\nshowToast('订阅成功,请支付发票');\nloadInvoices();\nloadSubscription()\n}).catch(function(e){alert('订阅失败: '+e.message)})}\n\nfunction payInvoice(invoiceId){\nif(!confirm('确定支付?'))return;\napi('/api/billing/pay/'+invoiceId,{method:'POST',body:JSON.stringify({method:'alipay'})}).then(function(){\nshowToast('支付成功!');\nloadInvoices();\nloadSubscription()\n}).catch(function(e){alert('支付失败: '+e.message)})}\n\n// ========== RBAC 权限 ==========\nfunction loadMyPermissions(){\napi('/api/rbac/my-permissions').then(function(data){\nvar html=data.permissions.map(function(p){\nreturn'<span class=\"tag tag-primary\">'+p+'</span>'\n}).join('');\n$('myPermissions').innerHTML=html||'<span style=\"color:var(--text2)\">暂无权限</span>'\n}).catch(function(){})}\n\nfunction loadRoles(){\napi('/api/rbac/roles').then(function(data){\nvar html=data.map(function(r){\nvar perms=JSON.parse(r.permissions||'[]');\nreturn'<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong>'+r.name+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.description+'</span></div><div style=\"display:flex;flex-wrap:wrap;gap:6px\">'+perms.map(function(p){return'<span class=\"tag\">'+p+'</span>'}).join('')+'</div></div>'\n}).join('');\n$('rolesList').innerHTML=html\n}).catch(function(){})}\n\nfunction showCreateRoleModal(){\nvar html='<div class=\"form-group\"><label>角色名称</label><input type=\"text\" id=\"newRoleName\" placeholder=\"role_name\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"newRoleDesc\" placeholder=\"角色描述\"></div><div class=\"form-group\"><label>权限(逗号分隔)</label><input type=\"text\" id=\"newRolePerms\" placeholder=\"chat,notes,memory\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createRole()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'roleModal\\')\">取消</button></div>';\nshowCustomModal('创建角色',html,'roleModal')}\n\nfunction createRole(){\nvar name=$('newRoleName').value.trim();\nvar desc=$('newRoleDesc').value.trim();\nvar perms=$('newRolePerms').value.split(',').map(function(p){return p.trim()}).filter(function(p){return p});\nif(!name){alert('请输入角色名称');return}\napi('/api/rbac/roles',{method:'POST',body:JSON.stringify({name:name,description:desc,permissions:perms})}).then(function(){\ncloseModal('roleModal');\nloadRoles();\nshowToast('角色已创建')\n}).catch(function(e){alert('创建失败: '+e.message)})}\n\n// 初始化时加载推荐\nsetTimeout(loadRecommendations,1000);\nsetTimeout(loadIntegrations,100);\n\n// ========== 快捷键帮助 ==========\nfunction showHotkeyHelp(){\nvar html='<div style=\"display:grid;gap:8px\">';\nvar hotkeys=[\n['Ctrl + N','新建对话'],\n['Ctrl + K','全局搜索'],\n['Ctrl + D','切换主题'],\n['Ctrl + H','系统状态'],\n['Ctrl + B','批量选择'],\n['Ctrl + F','搜索当前对话'],\n['Ctrl + /','快捷键帮助'],\n['Enter','发送消息'],\n['Shift + Enter','换行'],\n['Escape','关闭弹窗']\n];\nhotkeys.forEach(function(h){\nhtml+='<div class=\"hotkey-help-item\"><span>'+h[1]+'</span><span class=\"hotkey-help-key\">'+h[0]+'</span></div>'\n});\nhtml+='</div>';\nshowCustomModal('⌨️ 快捷键帮助',html,'hotkeyHelpModal')}\n\n// ========== 欢迎引导 ==========\nfunction showWelcomeGuide(){\nif(localStorage.getItem('welcomeShown'))return;\nvar html='<div style=\"text-align:center;padding:20px\"><div style=\"font-size:48px;margin-bottom:16px\">🤖</div><h2 style=\"margin-bottom:12px\">欢迎使用 AI Hub</h2><p style=\"color:var(--text2);margin-bottom:24px\">一站式 AI 平台,支持多模型、多功能</p><div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:12px;text-align:left;margin-bottom:24px\"><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">💬</span><div style=\"font-weight:500;margin-top:8px\">多模型对话</div><div style=\"font-size:12px;color:var(--text2)\">支持 OpenAI、Claude、Gemini 等</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">🎨</span><div style=\"font-weight:500;margin-top:8px\">图片生成</div><div style=\"font-size:12px;color:var(--text2)\">DALL-E 3 AI 绘图</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">📚</span><div style=\"font-weight:500;margin-top:8px\">知识库</div><div style=\"font-size:12px;color:var(--text2)\">上传文档,智能问答</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">👥</span><div style=\"font-weight:500;margin-top:8px\">团队协作</div><div style=\"font-size:12px;color:var(--text2)\">多人共享对话和资源</div></div></div><button class=\"btn btn-primary\" onclick=\"closeModal(\\'welcomeModal\\');localStorage.setItem(\\'welcomeShown\\',\\'1\\')\">开始使用</button></div>';\nshowCustomModal('',html,'welcomeModal')}\nsetTimeout(showWelcomeGuide,500);\n\nconsole.log('🤖 AI Hub v2.0.0 - Enhanced');\n</script>\n</body>\n</html>\n"}, "37a4b16c61de4139d3d8664577b60691a79c5190": {"t": 1785765461.7286084, "n": 233526, "h": "67915a6b7c5ab00c", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"theme-color\" content=\"#0f0f1a\">\n<meta name=\"description\" content=\"AI Hub - 统一 AI 平台\">\n<link rel=\"manifest\" href=\"/static/manifest.json\">\n<link rel=\"apple-touch-icon\" href=\"/static/icon-192.png\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"traces\"><span class=\"nav-item-icon\">🔍</span> 链路追踪</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n<div class=\"nav-item\" data-page=\"rag\"><span class=\"nav-item-icon\">🔍</span> RAG 检索</div>\n<div class=\"nav-item\" data-page=\"billing\"><span class=\"nav-item-icon\">💳</span> 订阅计费</div>\n<div class=\"nav-item\" data-page=\"rbac\"><span class=\"nav-item-icon\">🛡️</span> 权限管理</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"integrations\"><span class=\"nav-item-icon\">🔗</span> 第三方集成</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"workflows\"><span class=\"nav-item-icon\">🤖</span> Agent 工作流</div>\n<div class=\"nav-item\" data-page=\"code-runner\"><span class=\"nav-item-icon\">▶️</span> 代码运行</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" onclick=\"showHealthDashboard()\"><span class=\"nav-item-icon\">🖥️</span> 系统状态</div>\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\" title=\"批量操作\">☑️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div id=\"batchActions\" style=\"display:none;padding:8px;background:var(--bg3);gap:8px;align-items:center\">\n<span style=\"font-size:12px\">已选 <span id=\"selectedCount\">0</span> 个</span>\n<button class=\"btn btn-danger btn-sm\" onclick=\"batchDeleteChats()\">删除</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"batchExportChats()\">导出</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\">取消</button>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"quickReplies\" style=\"display:none;padding:8px 0;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap\"></div>\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateImage()\" title=\"生成图片\">🎨</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateMindmap()\" title=\"生成思维导图\">🧠</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"saveAsTemplate()\" title=\"保存为模板\">💾</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">双因素认证 (2FA)<br><small style=\"color:var(--text2)\">使用 Google Authenticator 等应用增强账户安全</small></div><div style=\"display:flex;gap:8px\"><span id=\"2faStatus\" style=\"color:var(--text2)\">未启用</span><button class=\"btn btn-ghost btn-sm\" onclick=\"setup2FA()\" id=\"2faBtn\">设置</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录设备管理</div><button class=\"btn btn-ghost btn-sm\" onclick=\"alert('功能开发中')\">查看设备</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">修改密码</div><button class=\"btn btn-ghost btn-sm\" onclick=\"showChangePasswordModal()\">修改</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复<br><small style=\"color:var(--text2)\">导出/导入所有数据(对话、笔记、记忆、设置)</small></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-primary\" onclick=\"exportAllData()\">📤 导出全部</button><button class=\"btn btn-ghost\" onclick=\"importAllData()\">📥 导入数据</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据库优化<br><small style=\"color:var(--text2)\">清理过期数据,优化数据库性能</small></div><button class=\"btn btn-ghost\" onclick=\"optimizeDatabase()\">🔧 优化数据库</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n<button class=\"btn btn-primary\" onclick=\"showUsageAnalytics()\">📈 详细分析</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 链路追踪页 -->\n<div id=\"page-traces\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔍</span> 链路追踪</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"loadTraces()\">🔄 刷新</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportTraces()\">📥 导出</button>\n</div>\n</div>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:20px\">监控 API 请求的完整调用链路,分析性能瓶颈</p>\n<div id=\"tracesList\"><p style=\"color:var(--text2)\">点击刷新加载追踪记录</p></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 性能概览</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--accent)\" id=\"traceAvgLatency\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">平均延迟</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--success)\" id=\"traceSuccessRate\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">成功率</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--warning)\" id=\"traceCount\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总追踪数</div>\n</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- RAG 检索页 -->\n<div id=\"page-rag\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> RAG 语义检索</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">基于向量的语义搜索,让 AI 理解你的文档内容</p>\n<div class=\"form-group\"><label>选择知识库</label><select id=\"ragKbSelect\" style=\"width:100%;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select></div>\n<div class=\"form-group\"><label>搜索问题</label><input type=\"text\" id=\"ragQuery\" placeholder=\"输入你的问题...\"></div>\n<button class=\"btn btn-primary\" onclick=\"searchRAG()\">🔍 语义搜索</button>\n<button class=\"btn btn-ghost\" onclick=\"chatWithRAG()\" style=\"margin-left:8px\">💬 RAG 对话</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 搜索结果</h4>\n<div id=\"ragResults\" style=\"min-height:100px\"><p style=\"color:var(--text2)\">输入问题后点击搜索</p></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📤</span> 索引文档</h4>\n<div class=\"form-group\"><label>文档内容</label><textarea id=\"ragContent\" rows=\"6\" placeholder=\"粘贴文档内容...\"></textarea></div>\n<div class=\"form-group\"><label>文件名</label><input type=\"text\" id=\"ragFilename\" placeholder=\"document.txt\"></div>\n<button class=\"btn btn-primary\" onclick=\"indexDocument()\">📥 索引文档</button>\n</div>\n</div></div></div></div>\n<!-- 订阅计费页 -->\n<div id=\"page-billing\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💳</span> 订阅计费</h4>\n<div id=\"currentSubscription\" style=\"padding:20px;background:var(--bg);border-radius:12px;margin-bottom:20px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div><div style=\"font-size:12px;color:var(--text2)\">当前套餐</div><div style=\"font-size:24px;font-weight:600\" id=\"currentPlanName\">免费版</div></div>\n<div style=\"text-align:right\"><div style=\"font-size:12px;color:var(--text2)\">剩余额度</div><div style=\"font-size:24px;font-weight:600;color:var(--accent)\" id=\"remainingQuota\">10,000</div></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 套餐选择</h4>\n<div id=\"billingPlans\" class=\"price-cards\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 用量统计</h4>\n<div id=\"usageStats\" style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🧾</span> 发票记录</h4>\n<div id=\"invoiceList\"></div>\n</div>\n</div></div></div></div>\n<!-- 权限管理页 -->\n<div id=\"page-rbac\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🛡️</span> 权限管理</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">基于角色的访问控制 (RBAC)</p>\n<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<div style=\"font-size:12px;color:var(--text2);margin-bottom:8px\">我的权限</div>\n<div id=\"myPermissions\" style=\"display:flex;flex-wrap:wrap;gap:8px\"></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👥</span> 角色列表</h4>\n<div id=\"rolesList\"></div>\n<button class=\"btn btn-ghost\" onclick=\"showCreateRoleModal()\" style=\"margin-top:12px\">+ 创建角色</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> 权限说明</h4>\n<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:12px;font-size:13px\">\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>chat</strong> - 对话功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>notes</strong> - 笔记功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>memory</strong> - 全局记忆</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>image</strong> - 图片生成</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>code</strong> - 代码运行</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>rag</strong> - RAG 检索</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>admin</strong> - 管理功能</div>\n<div style=\"padding:12px;background:var(--bg);border-radius:8px\"><strong>*</strong> - 所有权限</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- 第三方集成页 -->\n<div id=\"page-integrations\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔗</span> 第三方集成</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:20px\">连接 Slack、飞书等平台,让 AI 助手无处不在</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> Slack 集成</h4>\n<div class=\"form-group\"><label>Bot Token</label><input type=\"password\" id=\"slackToken\" placeholder=\"xoxb-...\" onchange=\"saveIntegration('slack')\"></div>\n<div class=\"form-group\"><label>Signing Secret</label><input type=\"password\" id=\"slackSecret\" placeholder=\"签名密钥\" onchange=\"saveIntegration('slack')\"></div>\n<div class=\"form-group\"><label>Webhook URL</label><div style=\"display:flex;gap:8px\"><input type=\"text\" value=\"http://localhost:8000/api/integrations/slack/webhook\" readonly style=\"flex:1;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText(this.previousElementSibling.value)\">📋</button></div></div>\n<div style=\"display:flex;gap:12px;margin-top:16px\">\n<button class=\"btn btn-primary\" onclick=\"testSlackIntegration()\">🧪 测试连接</button>\n<button class=\"btn btn-ghost\" onclick=\"window.open('https://api.slack.com/apps','_blank')\">📖 创建 Slack App</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐦</span> 飞书集成</h4>\n<div class=\"form-group\"><label>App ID</label><input type=\"text\" id=\"feishuAppId\" placeholder=\"cli_...\" onchange=\"saveIntegration('feishu')\"></div>\n<div class=\"form-group\"><label>App Secret</label><input type=\"password\" id=\"feishuSecret\" placeholder=\"应用密钥\" onchange=\"saveIntegration('feishu')\"></div>\n<div class=\"form-group\"><label>Webhook URL</label><div style=\"display:flex;gap:8px\"><input type=\"text\" value=\"http://localhost:8000/api/integrations/feishu/webhook\" readonly style=\"flex:1;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText(this.previousElementSibling.value)\">📋</button></div></div>\n<div style=\"display:flex;gap:12px;margin-top:16px\">\n<button class=\"btn btn-primary\" onclick=\"testFeishuIntegration()\">🧪 测试连接</button>\n<button class=\"btn btn-ghost\" onclick=\"window.open('https://open.feishu.cn/app','_blank')\">📖 创建飞书应用</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> Webhook 通知</h4>\n<div class=\"form-group\"><label>通知 URL</label><input type=\"text\" id=\"webhookUrl\" placeholder=\"https://your-server.com/webhook\" onchange=\"saveIntegration('webhook')\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">新消息通知</div><label class=\"switch\"><input type=\"checkbox\" id=\"webhookNewMsg\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">错误通知</div><label class=\"switch\"><input type=\"checkbox\" id=\"webhookError\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🎛️</span> 灰度发布</h4>\n<div id=\"featureFlagsList\"></div>\n<button class=\"btn btn-ghost\" onclick=\"loadFeatureFlags()\" style=\"margin-top:12px\">🔄 刷新</button>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Agent 工作流页 -->\n<div id=\"page-workflows\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🤖</span> Agent 工作流</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建多步骤自动化任务,让 AI 按流程完成复杂工作</p>\n<div id=\"workflowTemplates\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px\"></div>\n</div>\n<div class=\"settings-section\" id=\"workflowRunner\" style=\"display:none\">\n<h4><span>▶️</span> 运行工作流</h4>\n<div id=\"workflowInputs\"></div>\n<button class=\"btn btn-primary\" onclick=\"executeWorkflow()\">🚀 执行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('workflowRunner').style.display='none'\">取消</button>\n</div>\n<div class=\"settings-section\" id=\"workflowResults\" style=\"display:none\">\n<h4><span>📋</span> 执行结果</h4>\n<div id=\"workflowResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 代码运行器页 -->\n<div id=\"page-code-runner\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>▶️</span> 代码运行器</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">在线运行 Python / JavaScript 代码</p>\n<div class=\"form-group\">\n<label>语言</label>\n<select id=\"codeLanguage\" style=\"width:150px\">\n<option value=\"python\">Python</option>\n<option value=\"javascript\">JavaScript</option>\n</select>\n</div>\n<div class=\"form-group\">\n<label>代码</label>\n<textarea id=\"codeInput\" rows=\"12\" style=\"font-family:monospace;font-size:13px\" placeholder=\"# 输入代码...\nprint('Hello, World!')\"></textarea>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-primary\" onclick=\"runCode()\">▶️ 运行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('codeInput').value=''\">清空</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 输出结果</h4>\n<pre id=\"codeOutput\" style=\"background:var(--bg);padding:16px;border-radius:8px;min-height:100px;font-family:monospace;font-size:13px;white-space:pre-wrap\">等待运行...</pre>\n</div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>系统状态</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + H</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量选择模式</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + B</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量导出</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>搜索当前对话</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + F</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换主题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + D</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><div class=\"form-group\" id=\"auth2FAGroup\" style=\"display:none\"><label>2FA 验证码</label><input type=\"text\" id=\"auth2FACode\" placeholder=\"6位验证码\" maxlength=\"6\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><div style=\"display:flex;align-items:center;margin:16px 0\"><div style=\"flex:1;height:1px;background:var(--border)\"></div><span style=\"padding:0 12px;color:var(--text2);font-size:12px\">或</span><div style=\"flex:1;height:1px;background:var(--border)\"></div></div><button class=\"btn btn-ghost\" style=\"width:100%;display:flex;align-items:center;justify-content:center;gap:8px\" onclick=\"loginWithGithub()\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg> 使用 GitHub 登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();if(n.dataset.page==='workflows')loadWorkflowTemplates();if(n.dataset.page==='traces')loadTraces();if(n.dataset.page==='integrations')loadFeatureFlags();if(n.dataset.page==='rag')loadRAGKnowledgeBases();if(n.dataset.page==='billing'){loadBillingPlans();loadSubscription();loadUsageStats();loadInvoices()}if(n.dataset.page==='rbac'){loadMyPermissions();loadRoles()}closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{\n// 先显示置顶的对话\nvar pinnedChats=chats.filter(function(c){return c.pinned});\nvar normalChats=chats.filter(function(c){return !c.pinned&&!c.archived});\nif(pinnedChats.length>0){html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2)\">📌 置顶</div>';pinnedChats.forEach(function(c){html+=renderChatItem(c)})}\nif(normalChats.length>0){if(pinnedChats.length>0)html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2);margin-top:8px\">💬 对话</div>';normalChats.forEach(function(c){html+=renderChatItem(c)})}}$('chatList').innerHTML=html}\nfunction renderChatItem(c){var selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';var checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';var pinIcon=c.pinned?'📌':'💬';return'<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" style=\"'+selected+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">'+pinIcon+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"favoriteMessageByIndex('+i+')\" title=\"收藏\">❤️</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll();showQuickReplies()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var chat=chats.find(function(c){return c.id===id});var pinText=chat&&chat.pinned?'📌 取消置顶':'📌 置顶';var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"togglePinChat(\\''+id+'\\')\">'+pinText+'</div><div onclick=\"archiveChat(\\''+id+'\\')\">📦 归档</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction togglePinChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.pinned=!chat.pinned;saveChats();renderChats();showToast(chat.pinned?'已置顶':'已取消置顶');if(authToken){api('/api/conversations/'+id+'/pin',{method:'POST'}).catch(function(){})}}\nfunction archiveChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.archived=true;chats=chats.filter(function(c){return c.id!==id});saveChats();renderChats();showToast('已归档');if(authToken){api('/api/conversations/'+id+'/archive',{method:'POST'}).catch(function(){})}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Agent 工作流\nvar workflowTemplates=[];\nvar currentWorkflow=null;\nfunction loadWorkflowTemplates(){api('/api/workflows/templates').then(function(data){workflowTemplates=data;renderWorkflowTemplates()}).catch(function(e){console.error('加载工作流失败:',e)})}\nfunction renderWorkflowTemplates(){var html=workflowTemplates.map(function(w){return'<div style=\"background:var(--bg);border-radius:12px;padding:20px;cursor:pointer\" onclick=\"selectWorkflow(\\''+w.id+'\\')\"><div style=\"display:flex;align-items:center;gap:12px;margin-bottom:12px\"><span style=\"font-size:24px\">🤖</span><div><strong>'+w.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+w.steps.length+' 个步骤</div></div></div><p style=\"font-size:13px;color:var(--text2);line-height:1.5\">'+w.description+'</p></div>'}).join('');$('workflowTemplates').innerHTML=html||'<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无工作流模板</div>'}\nfunction selectWorkflow(id){currentWorkflow=workflowTemplates.find(function(w){return w.id===id});if(!currentWorkflow)return;var inputs=[];currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')&&inputs.indexOf(key)===-1)inputs.push(key)})}});var html=inputs.map(function(key){return'<div class=\"form-group\"><label>'+key+'</label><textarea id=\"wf_'+key+'\" rows=\"3\" placeholder=\"输入 '+key+'\"></textarea></div>'}).join('');$('workflowInputs').innerHTML='<h5 style=\"margin-bottom:16px\">'+currentWorkflow.name+'</h5>'+html;$('workflowRunner').style.display='block';$('workflowResults').style.display='none'}\nfunction executeWorkflow(){if(!currentWorkflow){alert('请先选择工作流');return}var inputData={};currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')){var el=$('wf_'+key);if(el)inputData[key]=el.value}})}});$('workflowResultsContent').innerHTML='<div style=\"text-align:center;padding:40px\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px;color:var(--text2)\">正在执行工作流...</p></div>';$('workflowResults').style.display='block';api('/api/workflows/run',{method:'POST',body:JSON.stringify({name:currentWorkflow.name,steps:currentWorkflow.steps,input_data:inputData})}).then(function(data){var html='';for(var key in data.results){html+='<div style=\"background:var(--bg);border-radius:10px;padding:16px;margin-bottom:12px\"><div style=\"font-weight:600;margin-bottom:8px;color:var(--accent)\">'+key+'</div><div style=\"font-size:14px;line-height:1.6;white-space:pre-wrap\">'+data.results[key]+'</div></div>'}$('workflowResultsContent').innerHTML=html}).catch(function(e){$('workflowResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">执行失败: '+e.message+'</div>'})}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// GitHub 登录\nfunction loginWithGithub(){window.location.href='/api/auth/github'}\n// 2FA 设置\nfunction setup2FA(){if(!authToken){alert('请先登录');return}api('/api/auth/2fa/setup',{method:'POST'}).then(function(data){var html='<div style=\"text-align:center\"><img src=\"'+data.qr_code+'\" style=\"width:200px;height:200px;border-radius:8px\"><p style=\"margin:16px 0;color:var(--text2);font-size:13px\">使用 Google Authenticator 扫描二维码</p><div class=\"form-group\"><label>输入6位验证码确认</label><input type=\"text\" id=\"verify2FACode\" placeholder=\"000000\" maxlength=\"6\" style=\"text-align:center;font-size:20px;letter-spacing:8px\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"verify2FA()\">确认启用</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'2faModal\\')\">取消</button></div></div>';showCustomModal('设置双因素认证',html,'2faModal')}).catch(function(e){alert('设置失败: '+e.message)})}\nfunction verify2FA(){var code=$('verify2FACode').value.trim();if(code.length!==6){alert('请输入6位验证码');return}api('/api/auth/2fa/verify',{method:'POST',body:JSON.stringify({code:code})}).then(function(data){closeModal('2faModal');$('2faStatus').textContent='已启用';$('2faStatus').style.color='var(--success)';$('2faBtn').textContent='禁用';$('2faBtn').onclick=disable2FA;showToast('2FA 已启用')}).catch(function(e){alert('验证失败: '+e.message)})}\nfunction disable2FA(){var code=prompt('输入6位验证码以禁用 2FA:');if(!code)return;api('/api/auth/2fa/disable',{method:'POST',body:JSON.stringify({code:code})}).then(function(){$('2faStatus').textContent='未启用';$('2faStatus').style.color='var(--text2)';$('2faBtn').textContent='设置';$('2faBtn').onclick=setup2FA;showToast('2FA 已禁用')}).catch(function(e){alert('禁用失败: '+e.message)})}\nfunction showChangePasswordModal(){var html='<div class=\"form-group\"><label>当前密码</label><input type=\"password\" id=\"oldPassword\"></div><div class=\"form-group\"><label>新密码</label><input type=\"password\" id=\"newPassword\"></div><div class=\"form-group\"><label>确认新密码</label><input type=\"password\" id=\"confirmPassword\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"changePassword()\">修改</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pwdModal\\')\">取消</button></div>';showCustomModal('修改密码',html,'pwdModal')}\nfunction changePassword(){var oldPwd=$('oldPassword').value,newPwd=$('newPassword').value,confirmPwd=$('confirmPassword').value;if(!oldPwd||!newPwd){alert('请填写密码');return}if(newPwd!==confirmPwd){alert('两次密码不一致');return}alert('密码修改功能开发中')}\n// 检查 URL 中的 token(OAuth 回调)\n(function(){var params=new URLSearchParams(window.location.search);var token=params.get('token');if(token){localStorage.setItem('token',token);authToken=token;window.history.replaceState({},document.title,'/');checkAuth()}})();\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\n// 代码运行器\nfunction runCode(){var code=$('codeInput').value;var lang=$('codeLanguage').value;if(!code.trim()){alert('请输入代码');return}$('codeOutput').textContent='运行中...';$('codeOutput').style.color='var(--text2)';api('/api/code/run',{method:'POST',body:JSON.stringify({code:code,language:lang,timeout:5})}).then(function(data){if(data.success){$('codeOutput').textContent=data.output||'(无输出)';$('codeOutput').style.color='var(--success)'}else{$('codeOutput').textContent='错误: '+(data.error||'未知错误')+'\\n'+data.output;$('codeOutput').style.color='var(--error)'}}).catch(function(e){$('codeOutput').textContent='请求失败: '+e.message;$('codeOutput').style.color='var(--error)'})}\n// 思维导图\nfunction generateMindmap(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}showToast('正在生成思维导图...');api('/api/mindmap/generate',{method:'POST',body:JSON.stringify({messages:chat.messages,title:chat.title})}).then(function(data){renderMindmap(data.nodes)}).catch(function(e){alert('生成失败: '+e.message)})}\nfunction renderMindmap(nodes){var html='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.8);z-index:2000;display:flex;align-items:center;justify-content:center\" onclick=\"if(event.target===this)this.remove()\"><div style=\"background:var(--bg2);border-radius:16px;padding:24px;max-width:800px;max-height:80vh;overflow:auto\"><h3 style=\"margin-bottom:16px\">🧠 思维导图</h3><div id=\"mindmapContent\" style=\"padding:20px\"></div><button class=\"btn btn-ghost\" onclick=\"this.parentElement.parentElement.remove()\">关闭</button></div></div>';document.body.insertAdjacentHTML('beforeend',html);var content='';function renderNode(node,level){var indent=level*24;content+='<div style=\"margin-left:'+indent+'px;padding:8px 12px;margin-bottom:4px;background:var(--bg'+(level>0?'3':'')+');border-radius:6px;border-left:3px solid var(--accent)\">'+(level>0?'├─ ':'')+node.label+'</div>';if(node.children){node.children.forEach(function(c){renderNode(c,level+1)})}}if(nodes&&nodes.length)renderNode(nodes[0],0);$('mindmapContent').innerHTML=content||'<p style=\"color:var(--text2)\">无法生成思维导图</p>'}\n// 保存对话为模板\nfunction saveAsTemplate(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}var name=prompt('模板名称:',chat.title);if(!name)return;api('/api/chat-templates',{method:'POST',body:JSON.stringify({name:name,messages:chat.messages})}).then(function(){showToast('已保存为模板')}).catch(function(e){alert('保存失败: '+e.message)})}\n// 用量配额\nfunction loadQuota(){api('/api/quota').then(function(data){var html='<div style=\"margin-bottom:16px\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Token 使用量</span><span>'+formatNumber(data.tokens_used)+' / '+formatNumber(data.tokens_limit)+'</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;overflow:hidden\"><div style=\"background:var(--accent);height:100%;width:'+data.usage_percent+'%\"></div></div></div><p style=\"font-size:12px;color:var(--text2)\">当前套餐: '+data.plan+'</p>';if($('quotaInfo'))$('quotaInfo').innerHTML=html}).catch(function(e){console.error(e)})}\n// PWA 注册\nif('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js').then(function(reg){console.log('SW registered');if('Notification' in window&&Notification.permission==='default'){Notification.requestPermission()}}).catch(function(e){console.error('SW failed:',e)})}\n// 图片生成\nfunction generateImage(){var prompt=prompt('输入图片描述:');if(!prompt)return;showToast('正在生成图片...');api('/api/images/generate',{method:'POST',body:JSON.stringify({prompt:prompt})}).then(function(data){var img='<img src=\"'+data.url+'\" style=\"max-width:100%;border-radius:8px\">';var chat=chats.find(function(c){return c.id===currentChatId});if(chat){chat.messages.push({role:'assistant',content:'![生成的图片]('+data.url+')\\n\\n'+data.revised_prompt});saveChats();renderMessages()}showToast('图片已生成')}).catch(function(e){alert('生成失败: '+e.message)})}\n// TTS 语音合成\nfunction speakText(text){api('/api/audio/tts',{method:'POST',body:JSON.stringify({text:text,voice:'alloy'})}).then(function(data){var audio=new Audio(data.audio);audio.play();showToast('正在播放')}).catch(function(e){if('speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(text);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('TTS 失败: '+e.message)}})}\n// 内容过滤\nfunction filterContent(text){return api('/api/content/filter',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data})}\n// 数据脱敏\nfunction maskData(text){return api('/api/data/mask',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data.masked})}\n// 备份\nfunction createBackup(){api('/api/backup',{method:'POST'}).then(function(data){showToast('备份已创建: '+data.path)}).catch(function(e){alert('备份失败: '+e.message)})}\n// 离线检测\nwindow.addEventListener('online',function(){showToast('网络已恢复')});\nwindow.addEventListener('offline',function(){showToast('网络已断开,部分功能不可用')});\n\n// ========== 性能监控面板 ==========\nfunction showHealthDashboard(){\napi('/api/health/detailed').then(function(data){\nvar html='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">CPU 使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.cpu_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.cpu_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">内存使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.memory_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.memory_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">磁盘使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.disk_percent>90?'var(--error)':'var(--success)')+'\">'+data.system.disk_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">数据库延迟</div><div style=\"font-size:24px;font-weight:600;color:'+(data.components.database.latency_ms>100?'var(--warning)':'var(--success)')+'\">'+data.components.database.latency_ms+'ms</div></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:10px\">';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>缓存</span><span>'+data.components.cache.size+'/'+data.components.cache.max_size+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Redis</span><span style=\"color:'+(data.components.redis.status==='healthy'?'var(--success)':'var(--warning)')+'\">'+data.components.redis.status+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between\"><span>待处理任务</span><span>'+data.components.task_queue.pending_tasks+'</span></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;text-align:center;font-size:12px;color:var(--text2)\">版本 '+data.version+' · 运行时间 '+formatUptime(data.uptime_seconds)+'</div>';\nshowCustomModal('🖥️ 系统状态',html,'healthModal')\n}).catch(function(e){alert('获取状态失败: '+e.message)})}\nfunction formatUptime(seconds){var h=Math.floor(seconds/3600);var m=Math.floor((seconds%3600)/60);return h+'小时'+m+'分钟'}\n\n// ========== 批量操作 ==========\nvar batchMode=false;\nvar selectedChats=[];\nfunction toggleBatchMode(){batchMode=!batchMode;selectedChats=[];if(batchMode){$('batchActions').style.display='flex';showToast('已进入批量选择模式')}else{$('batchActions').style.display='none'}renderChatList()}\nfunction toggleChatSelection(id,e){if(!batchMode)return;e.stopPropagation();var idx=selectedChats.indexOf(id);if(idx>=0){selectedChats.splice(idx,1)}else{selectedChats.push(id)}renderChatList();$('selectedCount').textContent=selectedChats.length}\nfunction batchDeleteChats(){if(selectedChats.length===0){alert('请先选择对话');return}if(!confirm('确定删除 '+selectedChats.length+' 个对话?'))return;api('/api/conversations/batch-delete',{method:'POST',body:JSON.stringify({ids:selectedChats})}).then(function(data){showToast('已删除 '+data.deleted+' 个对话');selectedChats=[];batchMode=false;$('batchActions').style.display='none';loadChats()}).catch(function(e){alert('删除失败: '+e.message)})}\nfunction batchExportChats(){if(selectedChats.length===0){alert('请先选择对话');return}api('/api/messages/batch-export',{method:'POST',body:JSON.stringify({conversation_ids:selectedChats,format:'json'})}).then(function(data){var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='conversations_export.json';a.click();showToast('已导出 '+data.count+' 个对话')}).catch(function(e){alert('导出失败: '+e.message)})}\n\n// ========== 数据库优化 ==========\nfunction optimizeDatabase(){if(!confirm('确定要优化数据库?这将清理过期数据。'))return;showToast('正在优化...');api('/api/admin/optimize-db',{method:'POST'}).then(function(data){showToast(data.message)}).catch(function(e){alert('优化失败: '+e.message)})}\n\n// ========== 快捷键增强 ==========\ndocument.addEventListener('keydown',function(e){\nif(e.ctrlKey&&e.key==='h'){e.preventDefault();showHealthDashboard()}\nif(e.ctrlKey&&e.key==='b'){e.preventDefault();toggleBatchMode()}\nif(e.ctrlKey&&e.shiftKey&&e.key==='E'){e.preventDefault();batchExportChats()}\nif(e.ctrlKey&&e.key==='f'){e.preventDefault();searchInCurrentChat()}\nif(e.ctrlKey&&e.key==='/'||e.key==='?'){e.preventDefault();showHotkeyHelp()}\n});\n\n// ========== 性能优化:虚拟滚动 ==========\nfunction renderChatListVirtual(){\nvar container=$('chatList');\nvar itemHeight=60;\nvar visibleCount=Math.ceil(container.clientHeight/itemHeight)+2;\nvar scrollTop=container.scrollTop;\nvar startIndex=Math.floor(scrollTop/itemHeight);\nvar endIndex=Math.min(startIndex+visibleCount,chats.length);\nvar html='<div style=\"height:'+(startIndex*itemHeight)+'px\"></div>';\nfor(var i=startIndex;i<endIndex;i++){\nvar c=chats[i];\nvar active=c.id===currentChatId?'active':'';\nvar selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';\nvar checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';\nhtml+='<div class=\"sidebar-item '+active+'\" style=\"'+selected+'\" onclick=\"loadChat(\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+c.title+'</div><div class=\"sidebar-item-desc\">'+(c.messages.length||0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" style=\"opacity:0\" onclick=\"deleteChat(\\''+c.id+'\\',event)\">🗑️</button></div>'\n}\nhtml+='<div style=\"height:'+((chats.length-endIndex)*itemHeight)+'px\"></div>';\ncontainer.innerHTML=html}\n\n// ========== 请求重试机制 ==========\nasync function apiWithRetry(url,options,maxRetries=3){\nfor(var i=0;i<maxRetries;i++){\ntry{return await api(url,options)}\ncatch(e){\nif(i===maxRetries-1)throw e;\nawait new Promise(function(r){setTimeout(r,1000*(i+1))});\nconsole.log('Retrying request...',i+1)\n}}}\n\n// ========== 消息队列(离线支持) ==========\nvar offlineQueue=JSON.parse(localStorage.getItem('offlineQueue')||'[]');\nfunction queueOfflineMessage(msg){offlineQueue.push({msg:msg,time:Date.now()});localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))}\nfunction processOfflineQueue(){if(offlineQueue.length===0)return;showToast('正在发送离线消息...');var msg=offlineQueue.shift();localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue));sendMessageInternal(msg.msg).then(function(){processOfflineQueue()}).catch(function(){offlineQueue.unshift(msg);localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))})}\nwindow.addEventListener('online',processOfflineQueue);\n\n// ========== 智能预加载 ==========\nfunction preloadNextChat(){\nvar currentIdx=chats.findIndex(function(c){return c.id===currentChatId});\nif(currentIdx>=0&&currentIdx<chats.length-1){\nvar nextChat=chats[currentIdx+1];\nif(!nextChat.messages||nextChat.messages.length===0){\napi('/api/conversations/'+nextChat.id+'/messages').then(function(msgs){nextChat.messages=msgs})}}}\n\n// ========== 自动保存草稿 ==========\nvar draftTimer=null;\nfunction saveDraft(){var input=$('chatInput').value;if(input&&currentChatId){localStorage.setItem('draft_'+currentChatId,input)}}\nfunction loadDraft(){if(currentChatId){var draft=localStorage.getItem('draft_'+currentChatId);if(draft)$('chatInput').value=draft}}\nfunction clearDraft(){if(currentChatId)localStorage.removeItem('draft_'+currentChatId)}\n$('chatInput').addEventListener('input',function(){clearTimeout(draftTimer);draftTimer=setTimeout(saveDraft,1000)});\n\n// ========== 消息搜索增强 ==========\nfunction searchInCurrentChat(){var q=prompt('在当前对话中搜索:');if(!q)return;var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages)return;var results=chat.messages.filter(function(m){return m.content&&m.content.toLowerCase().includes(q.toLowerCase())});if(results.length===0){alert('未找到匹配消息');return}var html='<div style=\"max-height:400px;overflow-y:auto\">';results.forEach(function(m,i){html+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:4px\">'+(m.role==='user'?'👤 用户':'🤖 助手')+'</div><div style=\"font-size:14px\">'+m.content.slice(0,200)+(m.content.length>200?'...':'')+'</div></div>'});html+='</div>';showCustomModal('搜索结果 ('+results.length+')',html,'searchResultModal')}\n\n// ========== 快速回复 ==========\nvar quickReplies=[\n{id:'continue',text:'继续',prompt:'请继续'},\n{id:'explain',text:'解释',prompt:'请详细解释一下'},\n{id:'example',text:'举例',prompt:'请举个例子'},\n{id:'simplify',text:'简化',prompt:'请用更简单的语言解释'},\n{id:'code',text:'代码',prompt:'请给出代码示例'},\n{id:'summary',text:'总结',prompt:'请总结一下要点'}\n];\nfunction showQuickReplies(){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages||chat.messages.length===0){$('quickReplies').style.display='none';return}\nvar lastMsg=chat.messages[chat.messages.length-1];\nif(lastMsg.role!=='assistant'){$('quickReplies').style.display='none';return}\nvar html=quickReplies.map(function(r){return'<button class=\"btn btn-ghost btn-sm\" onclick=\"sendQuickReply(\\''+r.prompt+'\\')\">'+r.text+'</button>'}).join('');\n$('quickReplies').innerHTML=html;\n$('quickReplies').style.display='flex'}\nfunction sendQuickReply(prompt){$('chatInput').value=prompt;sendMessage()}\n\n// ========== 数据导入导出 ==========\nfunction exportAllData(){\nif(!authToken){alert('请先登录');return}\nshowToast('正在导出数据...');\napi('/api/data/export-all',{method:'POST'}).then(function(data){\nvar blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='ai_hub_backup_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})}\n\nfunction importAllData(){\nif(!authToken){alert('请先登录');return}\nvar input=document.createElement('input');\ninput.type='file';\ninput.accept='.json';\ninput.onchange=function(e){\nvar file=e.target.files[0];\nif(!file)return;\nvar reader=new FileReader();\nreader.onload=function(ev){\ntry{\nvar data=JSON.parse(ev.target.result);\nif(!confirm('确定要导入数据?这将添加 '+\n(data.conversations?data.conversations.length:0)+' 个对话、'+\n(data.notes?data.notes.length:0)+' 个笔记'))return;\napi('/api/data/import',{method:'POST',body:JSON.stringify(data)}).then(function(result){\nshowToast('导入完成: '+result.imported.conversations+' 对话, '+result.imported.notes+' 笔记');\nloadChats()\n}).catch(function(e){alert('导入失败: '+e.message)})\n}catch(e){alert('文件格式错误')}};\nreader.readAsText(file)};\ninput.click()}\n\n// ========== 智能推荐 ==========\nfunction loadRecommendations(){\napi('/api/recommendations').then(function(data){\nif(data.features&&data.features.length>0){\nvar html='<div style=\"padding:16px;background:var(--bg3);border-radius:10px;margin-bottom:16px\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:12px\">💡 推荐功能</div><div style=\"display:flex;gap:12px;flex-wrap:wrap\">';\ndata.features.forEach(function(f){\nhtml+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;cursor:pointer;flex:1;min-width:150px\" onclick=\"showFeatureGuide(\\''+f.name+'\\')\"><span style=\"font-size:20px\">'+f.icon+'</span><div style=\"font-size:14px;font-weight:500;margin-top:8px\">'+f.name+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+f.desc+'</div></div>'});\nhtml+='</div></div>';\nvar container=$('chatMessages');\nif(container&&container.querySelector('.empty-state')){\ncontainer.innerHTML=html+container.innerHTML}}\n}).catch(function(){})}\nfunction showFeatureGuide(name){\nvar guides={\n'知识库':'点击左侧导航的\"知识库\",创建知识库并上传文档,AI 将基于您的资料回答问题。',\n'团队协作':'点击左侧导航的\"团队空间\",创建团队并邀请成员,共享对话和资源。'\n};\nalert(guides[name]||'功能介绍开发中')}\n\n// ========== 收藏消息 ==========\nfunction favoriteMessage(content){\nif(!authToken){alert('请先登录');return}\napi('/api/messages/favorite',{method:'POST',body:JSON.stringify({\nconversation_id:currentChatId,\ncontent:content\n})}).then(function(){showToast('已收藏到记忆')}).catch(function(e){alert('收藏失败: '+e.message)})}\nfunction favoriteMessageByIndex(index){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages[index])return;\nfavoriteMessage(chat.messages[index].content)}\n\n// ========== 使用分析 ==========\nfunction showUsageAnalytics(){\napi('/api/analytics/usage?days=30').then(function(data){\nvar html='<div style=\"margin-bottom:20px\"><h4 style=\"margin-bottom:12px\">📊 30天使用趋势</h4>';\nif(data.daily_usage.length>0){\nvar maxCalls=Math.max.apply(null,data.daily_usage.map(function(d){return d.calls}));\nhtml+='<div style=\"display:flex;align-items:flex-end;gap:4px;height:100px\">';\ndata.daily_usage.forEach(function(d){\nvar height=Math.max(5,(d.calls/maxCalls)*100);\nhtml+='<div style=\"flex:1;background:var(--accent);border-radius:2px 2px 0 0;height:'+height+'px\" title=\"'+d.day+': '+d.calls+'次\"></div>'});\nhtml+='</div>'}\nhtml+='</div>';\nhtml+='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">总调用次数</div><div style=\"font-size:24px;font-weight:600\">'+data.total_calls+'</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">错误率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.error_rate>5?'var(--error)':'var(--success)')+'\">'+data.error_rate+'%</div></div>';\nhtml+='</div>';\nshowCustomModal('📈 使用分析',html,'analyticsModal')\n}).catch(function(e){alert('获取分析失败: '+e.message)})}\n\n// ========== 第三方集成 ==========\nfunction saveIntegration(type){\nvar data={};\nif(type==='slack'){\ndata={slack_token:$('slackToken').value,slack_secret:$('slackSecret').value}\n}else if(type==='feishu'){\ndata={feishu_app_id:$('feishuAppId').value,feishu_secret:$('feishuSecret').value}\n}else if(type==='webhook'){\ndata={webhook_url:$('webhookUrl').value,webhook_new_msg:$('webhookNewMsg').checked,webhook_error:$('webhookError').checked}\n}\nlocalStorage.setItem('integration_'+type,JSON.stringify(data));\nshowToast('配置已保存')}\n\nfunction loadIntegrations(){\ntry{\nvar slack=JSON.parse(localStorage.getItem('integration_slack')||'{}');\nif(slack.slack_token)$('slackToken').value=slack.slack_token;\nif(slack.slack_secret)$('slackSecret').value=slack.slack_secret;\nvar feishu=JSON.parse(localStorage.getItem('integration_feishu')||'{}');\nif(feishu.feishu_app_id)$('feishuAppId').value=feishu.feishu_app_id;\nif(feishu.feishu_secret)$('feishuSecret').value=feishu.feishu_secret;\nvar webhook=JSON.parse(localStorage.getItem('integration_webhook')||'{}');\nif(webhook.webhook_url)$('webhookUrl').value=webhook.webhook_url;\nif(webhook.webhook_new_msg)$('webhookNewMsg').checked=true;\nif(webhook.webhook_error)$('webhookError').checked=true;\n}catch(e){}}\n\nfunction testSlackIntegration(){\nshowToast('测试 Slack 连接...');\napi('/api/integrations/slack/send',{method:'POST',body:JSON.stringify({channel:'#general',text:'AI Hub 测试消息'})}).then(function(data){\nif(data.ok){showToast('Slack 连接成功!')}else{alert('连接失败: '+(data.error||'未知错误'))}\n}).catch(function(e){alert('连接失败: '+e.message)})}\n\nfunction testFeishuIntegration(){\nshowToast('测试飞书连接...');\napi('/api/integrations/feishu/send',{method:'POST',body:JSON.stringify({chat_id:'test',text:'AI Hub 测试消息'})}).then(function(data){\nif(data.code===0){showToast('飞书连接成功!')}else{alert('连接失败: '+(data.msg||'未知错误'))}\n}).catch(function(e){alert('连接失败: '+e.message)})}\n\n// ========== 灰度发布 ==========\nfunction loadFeatureFlags(){\napi('/api/features/all').then(function(data){\nvar html='';\nfor(var name in data){\nvar flag=data[name];\nhtml+='<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\">';\nhtml+='<div><strong>'+name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">灰度比例: '+flag.percentage+'% · 白名单用户: '+(flag.users?flag.users.length:0)+'</div></div>';\nhtml+='<label class=\"switch\"><input type=\"checkbox\" '+(flag.enabled?'checked':'')+' onchange=\"toggleFeatureFlag(\\''+name+'\\',this.checked)\"><span class=\"switch-slider\"></span></label>';\nhtml+='</div>'}\n$('featureFlagsList').innerHTML=html||'<p style=\"color:var(--text2)\">暂无功能开关</p>'\n}).catch(function(e){$('featureFlagsList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction toggleFeatureFlag(name,enabled){\napi('/api/features/'+name,{method:'POST',body:JSON.stringify({enabled:enabled})}).then(function(){\nshowToast(name+(enabled?' 已启用':' 已禁用'))\n}).catch(function(e){alert('操作失败: '+e.message)})}\n\nfunction updateFeatureFlagPercentage(name,percentage){\napi('/api/features/'+name,{method:'POST',body:JSON.stringify({percentage:parseInt(percentage)})}).then(function(){\nshowToast('灰度比例已更新')\n}).catch(function(e){alert('操作失败: '+e.message)})}\n\n// ========== 链路追踪 ==========\nfunction loadTraces(){\napi('/api/traces?limit=50').then(function(data){\nif(data.length===0){$('tracesList').innerHTML='<p style=\"color:var(--text2)\">暂无追踪记录</p>';return}\nvar html='<table style=\"width:100%;border-collapse:collapse;font-size:13px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">ID</th><th style=\"padding:10px\">名称</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">Spans</th></tr>';\ndata.forEach(function(t){\nhtml+='<tr style=\"border-top:1px solid var(--border);cursor:pointer\" onclick=\"showTraceDetail(\\''+t.id+'\\')\">';\nhtml+='<td style=\"padding:10px;font-family:monospace\">'+t.id+'</td>';\nhtml+='<td style=\"padding:10px\">'+t.name+'</td>';\nhtml+='<td style=\"padding:10px;text-align:right\">'+(t.total_duration?(t.total_duration*1000).toFixed(0)+'ms':'-')+'</td>';\nhtml+='<td style=\"padding:10px\">'+(t.spans?t.spans.length:0)+'</td>';\nhtml+='</tr>'});\nhtml+='</table>';\n$('tracesList').innerHTML=html\n}).catch(function(e){$('tracesList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction showTraceDetail(traceId){\napi('/api/traces/'+traceId).then(function(data){\nvar html='<div style=\"margin-bottom:16px\"><strong>Trace ID:</strong> '+data.id+'<br><strong>名称:</strong> '+data.name+'<br><strong>总耗时:</strong> '+(data.total_duration?(data.total_duration*1000).toFixed(0)+'ms':'-')+'</div>';\nif(data.spans&&data.spans.length>0){\nhtml+='<h4 style=\"margin-bottom:12px\">Spans</h4>';\ndata.spans.forEach(function(s,i){\nvar width=Math.min(100,s.duration*100);\nhtml+='<div style=\"margin-bottom:8px\"><div style=\"display:flex;justify-content:space-between;font-size:13px\"><span>'+s.name+'</span><span>'+(s.duration*1000).toFixed(0)+'ms</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;margin-top:4px\"><div style=\"background:var(--accent);height:100%;width:'+width+'%;border-radius:4px\"></div></div></div>'\n})}\nshowCustomModal('🔍 追踪详情',html,'traceDetailModal')\n}).catch(function(e){alert('加载失败: '+e.message)})}\n\nfunction exportTraces(){\napi('/api/traces?limit=100').then(function(data){\nif(data.length===0){alert('暂无追踪记录');return}\nvar traceIds=data.map(function(t){return t.id});\napi('/api/traces/export',{method:'POST',body:JSON.stringify({trace_ids:traceIds,format:'jaeger'})}).then(function(result){\nvar blob=new Blob([JSON.stringify(result.data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='traces_export_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('追踪数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})\n}).catch(function(e){alert('获取追踪失败: '+e.message)})}\n\n// ========== RAG 检索 ==========\nfunction loadRAGKnowledgeBases(){\napi('/api/knowledge-bases').then(function(data){\nvar html='<option value=\"\">选择知识库</option>';\ndata.forEach(function(kb){html+='<option value=\"'+kb.id+'\">'+kb.name+'</option>'});\n$('ragKbSelect').innerHTML=html\n}).catch(function(){})}\n\nfunction searchRAG(){\nvar kbId=$('ragKbSelect').value;\nvar query=$('ragQuery').value.trim();\nif(!kbId){alert('请选择知识库');return}\nif(!query){alert('请输入问题');return}\n$('ragResults').innerHTML='<p style=\"color:var(--text2)\">搜索中...</p>';\napi('/api/rag/search',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),query:query,top_k:5})}).then(function(data){\nif(data.results.length===0){$('ragResults').innerHTML='<p style=\"color:var(--text2)\">未找到相关内容</p>';return}\nvar html=data.results.map(function(r,i){\nreturn'<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px;border-left:4px solid var(--accent)\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span style=\"font-weight:500\">#'+(i+1)+' '+r.chunk_id+'</span><span style=\"color:var(--accent)\">相似度: '+(r.score*100).toFixed(1)+'%</span></div><div style=\"font-size:14px;color:var(--text2);line-height:1.6\">'+r.content.slice(0,300)+(r.content.length>300?'...':'')+'</div></div>'\n}).join('');\n$('ragResults').innerHTML=html\n}).catch(function(e){$('ragResults').innerHTML='<p style=\"color:var(--error)\">搜索失败: '+e.message+'</p>'})}\n\nfunction chatWithRAG(){\nvar kbId=$('ragKbSelect').value;\nvar query=$('ragQuery').value.trim();\nif(!kbId){alert('请选择知识库');return}\nif(!query){alert('请输入问题');return}\n$('ragResults').innerHTML='<p style=\"color:var(--text2)\">AI 正在思考...</p>';\napi('/api/rag/chat',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),question:query})}).then(function(data){\nvar html='<div style=\"padding:20px;background:var(--bg);border-radius:12px\"><div style=\"font-size:14px;line-height:1.8\">'+marked.parse(data.answer)+'</div>';\nif(data.sources&&data.sources.length>0){\nhtml+='<div style=\"margin-top:16px;padding-top:16px;border-top:1px solid var(--border)\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:8px\">参考来源:</div>';\ndata.sources.forEach(function(s){html+='<span class=\"tag\" style=\"margin-right:8px\">'+s.chunk_id+' ('+(s.score*100).toFixed(0)+'%)</span>'});\nhtml+='</div>'}\nhtml+='</div>';\n$('ragResults').innerHTML=html\n}).catch(function(e){$('ragResults').innerHTML='<p style=\"color:var(--error)\">对话失败: '+e.message+'</p>'})}\n\nfunction indexDocument(){\nvar kbId=$('ragKbSelect').value;\nvar content=$('ragContent').value.trim();\nvar filename=$('ragFilename').value.trim()||'document.txt';\nif(!kbId){alert('请选择知识库');return}\nif(!content){alert('请输入文档内容');return}\nshowToast('正在索引文档...');\napi('/api/rag/index',{method:'POST',body:JSON.stringify({kb_id:parseInt(kbId),content:content,filename:filename})}).then(function(data){\nshowToast('索引完成,共 '+data.indexed_chunks+' 个分块');\n$('ragContent').value='';\n$('ragFilename').value=''\n}).catch(function(e){alert('索引失败: '+e.message)})}\n\n// ========== 计费系统 ==========\nfunction loadBillingPlans(){\napi('/api/billing/plans').then(function(data){\nvar html=data.map(function(p){\nvar features=JSON.parse(p.features||'[]');\nreturn'<div class=\"price-card\" onclick=\"subscribePlan(\\''+p.id+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">¥'+p.price+'<span>/月</span></div><ul>'+features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn btn-primary\" style=\"width:100%\">选择</button></div>'\n}).join('');\n$('billingPlans').innerHTML=html\n}).catch(function(){})}\n\nfunction loadSubscription(){\napi('/api/billing/subscription').then(function(data){\n$('currentPlanName').textContent=data.plan_name||data.plan||'免费版';\nvar remaining=data.tokens_limit===-1?'无限':formatNumber(data.tokens_limit||10000);\n$('remainingQuota').textContent=remaining\n}).catch(function(){})}\n\nfunction loadUsageStats(){\napi('/api/billing/usage?period=month').then(function(data){\nvar html='';\nfor(var type in data.usage){\nvar u=data.usage[type];\nhtml+='<div style=\"padding:16px;background:var(--bg);border-radius:10px;text-align:center\"><div style=\"font-size:24px;font-weight:600;color:var(--accent)\">'+formatNumber(u.amount)+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+type+'</div><div style=\"font-size:11px;color:var(--success);margin-top:4px\">¥'+u.cost.toFixed(2)+'</div></div>'\n}\n$('usageStats').innerHTML=html||'<p style=\"color:var(--text2);grid-column:1/-1;text-align:center\">暂无用量数据</p>'\n}).catch(function(){})}\n\nfunction loadInvoices(){\napi('/api/billing/invoices').then(function(data){\nif(data.length===0){$('invoiceList').innerHTML='<p style=\"color:var(--text2)\">暂无发票</p>';return}\nvar html=data.map(function(inv){\nvar statusColor=inv.status==='paid'?'var(--success)':'var(--warning)';\nreturn'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div><div style=\"font-weight:500\">'+inv.id+'</div><div style=\"font-size:12px;color:var(--text2)\">'+(inv.created_at||'').slice(0,10)+'</div></div><div style=\"text-align:right\"><div style=\"font-weight:600\">¥'+inv.amount+'</div><div style=\"font-size:12px;color:'+statusColor+'\">'+(inv.status==='paid'?'已支付':'待支付')+'</div></div>'+(inv.status!=='paid'?'<button class=\"btn btn-primary btn-sm\" onclick=\"payInvoice(\\''+inv.id+'\\')\">支付</button>':'')+'</div>'\n}).join('');\n$('invoiceList').innerHTML=html\n}).catch(function(){})}\n\nfunction subscribePlan(planId){\nif(!authToken){alert('请先登录');return}\nif(!confirm('确定订阅此套餐?'))return;\napi('/api/billing/subscribe',{method:'POST',body:JSON.stringify({plan_id:planId,months:1})}).then(function(data){\nshowToast('订阅成功,请支付发票');\nloadInvoices();\nloadSubscription()\n}).catch(function(e){alert('订阅失败: '+e.message)})}\n\nfunction payInvoice(invoiceId){\nif(!confirm('确定支付?'))return;\napi('/api/billing/pay/'+invoiceId,{method:'POST',body:JSON.stringify({method:'alipay'})}).then(function(){\nshowToast('支付成功!');\nloadInvoices();\nloadSubscription()\n}).catch(function(e){alert('支付失败: '+e.message)})}\n\n// ========== RBAC 权限 ==========\nfunction loadMyPermissions(){\napi('/api/rbac/my-permissions').then(function(data){\nvar html=data.permissions.map(function(p){\nreturn'<span class=\"tag tag-primary\">'+p+'</span>'\n}).join('');\n$('myPermissions').innerHTML=html||'<span style=\"color:var(--text2)\">暂无权限</span>'\n}).catch(function(){})}\n\nfunction loadRoles(){\napi('/api/rbac/roles').then(function(data){\nvar html=data.map(function(r){\nvar perms=JSON.parse(r.permissions||'[]');\nreturn'<div style=\"padding:16px;background:var(--bg);border-radius:10px;margin-bottom:12px\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong>'+r.name+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.description+'</span></div><div style=\"display:flex;flex-wrap:wrap;gap:6px\">'+perms.map(function(p){return'<span class=\"tag\">'+p+'</span>'}).join('')+'</div></div>'\n}).join('');\n$('rolesList').innerHTML=html\n}).catch(function(){})}\n\nfunction showCreateRoleModal(){\nvar html='<div class=\"form-group\"><label>角色名称</label><input type=\"text\" id=\"newRoleName\" placeholder=\"role_name\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"newRoleDesc\" placeholder=\"角色描述\"></div><div class=\"form-group\"><label>权限(逗号分隔)</label><input type=\"text\" id=\"newRolePerms\" placeholder=\"chat,notes,memory\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createRole()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'roleModal\\')\">取消</button></div>';\nshowCustomModal('创建角色',html,'roleModal')}\n\nfunction createRole(){\nvar name=$('newRoleName').value.trim();\nvar desc=$('newRoleDesc').value.trim();\nvar perms=$('newRolePerms').value.split(',').map(function(p){return p.trim()}).filter(function(p){return p});\nif(!name){alert('请输入角色名称');return}\napi('/api/rbac/roles',{method:'POST',body:JSON.stringify({name:name,description:desc,permissions:perms})}).then(function(){\ncloseModal('roleModal');\nloadRoles();\nshowToast('角色已创建')\n}).catch(function(e){alert('创建失败: '+e.message)})}\n\n// 初始化时加载推荐\nsetTimeout(loadRecommendations,1000);\nsetTimeout(loadIntegrations,100);\n\n// ========== 快捷键帮助 ==========\nfunction showHotkeyHelp(){\nvar html='<div style=\"display:grid;gap:8px\">';\nvar hotkeys=[\n['Ctrl + N','新建对话'],\n['Ctrl + K','全局搜索'],\n['Ctrl + D','切换主题'],\n['Ctrl + H','系统状态'],\n['Ctrl + B','批量选择'],\n['Ctrl + F','搜索当前对话'],\n['Ctrl + /','快捷键帮助'],\n['Enter','发送消息'],\n['Shift + Enter','换行'],\n['Escape','关闭弹窗']\n];\nhotkeys.forEach(function(h){\nhtml+='<div class=\"hotkey-help-item\"><span>'+h[1]+'</span><span class=\"hotkey-help-key\">'+h[0]+'</span></div>'\n});\nhtml+='</div>';\nshowCustomModal('⌨️ 快捷键帮助',html,'hotkeyHelpModal')}\n\n// ========== 欢迎引导 ==========\nfunction showWelcomeGuide(){\nif(localStorage.getItem('welcomeShown'))return;\nvar html='<div style=\"text-align:center;padding:20px\"><div style=\"font-size:48px;margin-bottom:16px\">🤖</div><h2 style=\"margin-bottom:12px\">欢迎使用 AI Hub</h2><p style=\"color:var(--text2);margin-bottom:24px\">一站式 AI 平台,支持多模型、多功能</p><div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:12px;text-align:left;margin-bottom:24px\"><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">💬</span><div style=\"font-weight:500;margin-top:8px\">多模型对话</div><div style=\"font-size:12px;color:var(--text2)\">支持 OpenAI、Claude、Gemini 等</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">🎨</span><div style=\"font-weight:500;margin-top:8px\">图片生成</div><div style=\"font-size:12px;color:var(--text2)\">DALL-E 3 AI 绘图</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">📚</span><div style=\"font-weight:500;margin-top:8px\">知识库</div><div style=\"font-size:12px;color:var(--text2)\">上传文档,智能问答</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">👥</span><div style=\"font-weight:500;margin-top:8px\">团队协作</div><div style=\"font-size:12px;color:var(--text2)\">多人共享对话和资源</div></div></div><button class=\"btn btn-primary\" onclick=\"closeModal(\\'welcomeModal\\');localStorage.setItem(\\'welcomeShown\\',\\'1\\')\">开始使用</button></div>';\nshowCustomModal('',html,'welcomeModal')}\nsetTimeout(showWelcomeGuide,500);\n\nconsole.log('🤖 AI Hub v2.0.0 - Enhanced');\n</script>\n</body>\n</html>\n"}, "79b22e92aff1741013e8125d95440c03d8d8f370": {"t": 1785765463.7504447, "n": 220827, "h": "7015995be4023c0d", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"theme-color\" content=\"#0f0f1a\">\n<meta name=\"description\" content=\"AI Hub - 统一 AI 平台\">\n<link rel=\"manifest\" href=\"/static/manifest.json\">\n<link rel=\"apple-touch-icon\" href=\"/static/icon-192.png\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"traces\"><span class=\"nav-item-icon\">🔍</span> 链路追踪</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"integrations\"><span class=\"nav-item-icon\">🔗</span> 第三方集成</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"workflows\"><span class=\"nav-item-icon\">🤖</span> Agent 工作流</div>\n<div class=\"nav-item\" data-page=\"code-runner\"><span class=\"nav-item-icon\">▶️</span> 代码运行</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" onclick=\"showHealthDashboard()\"><span class=\"nav-item-icon\">🖥️</span> 系统状态</div>\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\" title=\"批量操作\">☑️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div id=\"batchActions\" style=\"display:none;padding:8px;background:var(--bg3);gap:8px;align-items:center\">\n<span style=\"font-size:12px\">已选 <span id=\"selectedCount\">0</span> 个</span>\n<button class=\"btn btn-danger btn-sm\" onclick=\"batchDeleteChats()\">删除</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"batchExportChats()\">导出</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\">取消</button>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"quickReplies\" style=\"display:none;padding:8px 0;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap\"></div>\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateImage()\" title=\"生成图片\">🎨</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateMindmap()\" title=\"生成思维导图\">🧠</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"saveAsTemplate()\" title=\"保存为模板\">💾</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">双因素认证 (2FA)<br><small style=\"color:var(--text2)\">使用 Google Authenticator 等应用增强账户安全</small></div><div style=\"display:flex;gap:8px\"><span id=\"2faStatus\" style=\"color:var(--text2)\">未启用</span><button class=\"btn btn-ghost btn-sm\" onclick=\"setup2FA()\" id=\"2faBtn\">设置</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录设备管理</div><button class=\"btn btn-ghost btn-sm\" onclick=\"alert('功能开发中')\">查看设备</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">修改密码</div><button class=\"btn btn-ghost btn-sm\" onclick=\"showChangePasswordModal()\">修改</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复<br><small style=\"color:var(--text2)\">导出/导入所有数据(对话、笔记、记忆、设置)</small></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-primary\" onclick=\"exportAllData()\">📤 导出全部</button><button class=\"btn btn-ghost\" onclick=\"importAllData()\">📥 导入数据</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据库优化<br><small style=\"color:var(--text2)\">清理过期数据,优化数据库性能</small></div><button class=\"btn btn-ghost\" onclick=\"optimizeDatabase()\">🔧 优化数据库</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n<button class=\"btn btn-primary\" onclick=\"showUsageAnalytics()\">📈 详细分析</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 链路追踪页 -->\n<div id=\"page-traces\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔍</span> 链路追踪</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"loadTraces()\">🔄 刷新</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportTraces()\">📥 导出</button>\n</div>\n</div>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:20px\">监控 API 请求的完整调用链路,分析性能瓶颈</p>\n<div id=\"tracesList\"><p style=\"color:var(--text2)\">点击刷新加载追踪记录</p></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 性能概览</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--accent)\" id=\"traceAvgLatency\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">平均延迟</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--success)\" id=\"traceSuccessRate\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">成功率</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:600;color:var(--warning)\" id=\"traceCount\">-</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总追踪数</div>\n</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- 第三方集成页 -->\n<div id=\"page-integrations\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔗</span> 第三方集成</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:20px\">连接 Slack、飞书等平台,让 AI 助手无处不在</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> Slack 集成</h4>\n<div class=\"form-group\"><label>Bot Token</label><input type=\"password\" id=\"slackToken\" placeholder=\"xoxb-...\" onchange=\"saveIntegration('slack')\"></div>\n<div class=\"form-group\"><label>Signing Secret</label><input type=\"password\" id=\"slackSecret\" placeholder=\"签名密钥\" onchange=\"saveIntegration('slack')\"></div>\n<div class=\"form-group\"><label>Webhook URL</label><div style=\"display:flex;gap:8px\"><input type=\"text\" value=\"http://localhost:8000/api/integrations/slack/webhook\" readonly style=\"flex:1;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText(this.previousElementSibling.value)\">📋</button></div></div>\n<div style=\"display:flex;gap:12px;margin-top:16px\">\n<button class=\"btn btn-primary\" onclick=\"testSlackIntegration()\">🧪 测试连接</button>\n<button class=\"btn btn-ghost\" onclick=\"window.open('https://api.slack.com/apps','_blank')\">📖 创建 Slack App</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐦</span> 飞书集成</h4>\n<div class=\"form-group\"><label>App ID</label><input type=\"text\" id=\"feishuAppId\" placeholder=\"cli_...\" onchange=\"saveIntegration('feishu')\"></div>\n<div class=\"form-group\"><label>App Secret</label><input type=\"password\" id=\"feishuSecret\" placeholder=\"应用密钥\" onchange=\"saveIntegration('feishu')\"></div>\n<div class=\"form-group\"><label>Webhook URL</label><div style=\"display:flex;gap:8px\"><input type=\"text\" value=\"http://localhost:8000/api/integrations/feishu/webhook\" readonly style=\"flex:1;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText(this.previousElementSibling.value)\">📋</button></div></div>\n<div style=\"display:flex;gap:12px;margin-top:16px\">\n<button class=\"btn btn-primary\" onclick=\"testFeishuIntegration()\">🧪 测试连接</button>\n<button class=\"btn btn-ghost\" onclick=\"window.open('https://open.feishu.cn/app','_blank')\">📖 创建飞书应用</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> Webhook 通知</h4>\n<div class=\"form-group\"><label>通知 URL</label><input type=\"text\" id=\"webhookUrl\" placeholder=\"https://your-server.com/webhook\" onchange=\"saveIntegration('webhook')\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">新消息通知</div><label class=\"switch\"><input type=\"checkbox\" id=\"webhookNewMsg\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">错误通知</div><label class=\"switch\"><input type=\"checkbox\" id=\"webhookError\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🎛️</span> 灰度发布</h4>\n<div id=\"featureFlagsList\"></div>\n<button class=\"btn btn-ghost\" onclick=\"loadFeatureFlags()\" style=\"margin-top:12px\">🔄 刷新</button>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Agent 工作流页 -->\n<div id=\"page-workflows\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🤖</span> Agent 工作流</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建多步骤自动化任务,让 AI 按流程完成复杂工作</p>\n<div id=\"workflowTemplates\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px\"></div>\n</div>\n<div class=\"settings-section\" id=\"workflowRunner\" style=\"display:none\">\n<h4><span>▶️</span> 运行工作流</h4>\n<div id=\"workflowInputs\"></div>\n<button class=\"btn btn-primary\" onclick=\"executeWorkflow()\">🚀 执行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('workflowRunner').style.display='none'\">取消</button>\n</div>\n<div class=\"settings-section\" id=\"workflowResults\" style=\"display:none\">\n<h4><span>📋</span> 执行结果</h4>\n<div id=\"workflowResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 代码运行器页 -->\n<div id=\"page-code-runner\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>▶️</span> 代码运行器</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">在线运行 Python / JavaScript 代码</p>\n<div class=\"form-group\">\n<label>语言</label>\n<select id=\"codeLanguage\" style=\"width:150px\">\n<option value=\"python\">Python</option>\n<option value=\"javascript\">JavaScript</option>\n</select>\n</div>\n<div class=\"form-group\">\n<label>代码</label>\n<textarea id=\"codeInput\" rows=\"12\" style=\"font-family:monospace;font-size:13px\" placeholder=\"# 输入代码...\nprint('Hello, World!')\"></textarea>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-primary\" onclick=\"runCode()\">▶️ 运行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('codeInput').value=''\">清空</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 输出结果</h4>\n<pre id=\"codeOutput\" style=\"background:var(--bg);padding:16px;border-radius:8px;min-height:100px;font-family:monospace;font-size:13px;white-space:pre-wrap\">等待运行...</pre>\n</div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>系统状态</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + H</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量选择模式</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + B</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量导出</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>搜索当前对话</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + F</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换主题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + D</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><div class=\"form-group\" id=\"auth2FAGroup\" style=\"display:none\"><label>2FA 验证码</label><input type=\"text\" id=\"auth2FACode\" placeholder=\"6位验证码\" maxlength=\"6\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><div style=\"display:flex;align-items:center;margin:16px 0\"><div style=\"flex:1;height:1px;background:var(--border)\"></div><span style=\"padding:0 12px;color:var(--text2);font-size:12px\">或</span><div style=\"flex:1;height:1px;background:var(--border)\"></div></div><button class=\"btn btn-ghost\" style=\"width:100%;display:flex;align-items:center;justify-content:center;gap:8px\" onclick=\"loginWithGithub()\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg> 使用 GitHub 登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();if(n.dataset.page==='workflows')loadWorkflowTemplates();if(n.dataset.page==='traces')loadTraces();if(n.dataset.page==='integrations')loadFeatureFlags();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{\n// 先显示置顶的对话\nvar pinnedChats=chats.filter(function(c){return c.pinned});\nvar normalChats=chats.filter(function(c){return !c.pinned&&!c.archived});\nif(pinnedChats.length>0){html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2)\">📌 置顶</div>';pinnedChats.forEach(function(c){html+=renderChatItem(c)})}\nif(normalChats.length>0){if(pinnedChats.length>0)html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2);margin-top:8px\">💬 对话</div>';normalChats.forEach(function(c){html+=renderChatItem(c)})}}$('chatList').innerHTML=html}\nfunction renderChatItem(c){var selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';var checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';var pinIcon=c.pinned?'📌':'💬';return'<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" style=\"'+selected+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">'+pinIcon+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"favoriteMessageByIndex('+i+')\" title=\"收藏\">❤️</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll();showQuickReplies()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var chat=chats.find(function(c){return c.id===id});var pinText=chat&&chat.pinned?'📌 取消置顶':'📌 置顶';var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"togglePinChat(\\''+id+'\\')\">'+pinText+'</div><div onclick=\"archiveChat(\\''+id+'\\')\">📦 归档</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction togglePinChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.pinned=!chat.pinned;saveChats();renderChats();showToast(chat.pinned?'已置顶':'已取消置顶');if(authToken){api('/api/conversations/'+id+'/pin',{method:'POST'}).catch(function(){})}}\nfunction archiveChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.archived=true;chats=chats.filter(function(c){return c.id!==id});saveChats();renderChats();showToast('已归档');if(authToken){api('/api/conversations/'+id+'/archive',{method:'POST'}).catch(function(){})}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Agent 工作流\nvar workflowTemplates=[];\nvar currentWorkflow=null;\nfunction loadWorkflowTemplates(){api('/api/workflows/templates').then(function(data){workflowTemplates=data;renderWorkflowTemplates()}).catch(function(e){console.error('加载工作流失败:',e)})}\nfunction renderWorkflowTemplates(){var html=workflowTemplates.map(function(w){return'<div style=\"background:var(--bg);border-radius:12px;padding:20px;cursor:pointer\" onclick=\"selectWorkflow(\\''+w.id+'\\')\"><div style=\"display:flex;align-items:center;gap:12px;margin-bottom:12px\"><span style=\"font-size:24px\">🤖</span><div><strong>'+w.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+w.steps.length+' 个步骤</div></div></div><p style=\"font-size:13px;color:var(--text2);line-height:1.5\">'+w.description+'</p></div>'}).join('');$('workflowTemplates').innerHTML=html||'<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无工作流模板</div>'}\nfunction selectWorkflow(id){currentWorkflow=workflowTemplates.find(function(w){return w.id===id});if(!currentWorkflow)return;var inputs=[];currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')&&inputs.indexOf(key)===-1)inputs.push(key)})}});var html=inputs.map(function(key){return'<div class=\"form-group\"><label>'+key+'</label><textarea id=\"wf_'+key+'\" rows=\"3\" placeholder=\"输入 '+key+'\"></textarea></div>'}).join('');$('workflowInputs').innerHTML='<h5 style=\"margin-bottom:16px\">'+currentWorkflow.name+'</h5>'+html;$('workflowRunner').style.display='block';$('workflowResults').style.display='none'}\nfunction executeWorkflow(){if(!currentWorkflow){alert('请先选择工作流');return}var inputData={};currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')){var el=$('wf_'+key);if(el)inputData[key]=el.value}})}});$('workflowResultsContent').innerHTML='<div style=\"text-align:center;padding:40px\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px;color:var(--text2)\">正在执行工作流...</p></div>';$('workflowResults').style.display='block';api('/api/workflows/run',{method:'POST',body:JSON.stringify({name:currentWorkflow.name,steps:currentWorkflow.steps,input_data:inputData})}).then(function(data){var html='';for(var key in data.results){html+='<div style=\"background:var(--bg);border-radius:10px;padding:16px;margin-bottom:12px\"><div style=\"font-weight:600;margin-bottom:8px;color:var(--accent)\">'+key+'</div><div style=\"font-size:14px;line-height:1.6;white-space:pre-wrap\">'+data.results[key]+'</div></div>'}$('workflowResultsContent').innerHTML=html}).catch(function(e){$('workflowResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">执行失败: '+e.message+'</div>'})}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// GitHub 登录\nfunction loginWithGithub(){window.location.href='/api/auth/github'}\n// 2FA 设置\nfunction setup2FA(){if(!authToken){alert('请先登录');return}api('/api/auth/2fa/setup',{method:'POST'}).then(function(data){var html='<div style=\"text-align:center\"><img src=\"'+data.qr_code+'\" style=\"width:200px;height:200px;border-radius:8px\"><p style=\"margin:16px 0;color:var(--text2);font-size:13px\">使用 Google Authenticator 扫描二维码</p><div class=\"form-group\"><label>输入6位验证码确认</label><input type=\"text\" id=\"verify2FACode\" placeholder=\"000000\" maxlength=\"6\" style=\"text-align:center;font-size:20px;letter-spacing:8px\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"verify2FA()\">确认启用</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'2faModal\\')\">取消</button></div></div>';showCustomModal('设置双因素认证',html,'2faModal')}).catch(function(e){alert('设置失败: '+e.message)})}\nfunction verify2FA(){var code=$('verify2FACode').value.trim();if(code.length!==6){alert('请输入6位验证码');return}api('/api/auth/2fa/verify',{method:'POST',body:JSON.stringify({code:code})}).then(function(data){closeModal('2faModal');$('2faStatus').textContent='已启用';$('2faStatus').style.color='var(--success)';$('2faBtn').textContent='禁用';$('2faBtn').onclick=disable2FA;showToast('2FA 已启用')}).catch(function(e){alert('验证失败: '+e.message)})}\nfunction disable2FA(){var code=prompt('输入6位验证码以禁用 2FA:');if(!code)return;api('/api/auth/2fa/disable',{method:'POST',body:JSON.stringify({code:code})}).then(function(){$('2faStatus').textContent='未启用';$('2faStatus').style.color='var(--text2)';$('2faBtn').textContent='设置';$('2faBtn').onclick=setup2FA;showToast('2FA 已禁用')}).catch(function(e){alert('禁用失败: '+e.message)})}\nfunction showChangePasswordModal(){var html='<div class=\"form-group\"><label>当前密码</label><input type=\"password\" id=\"oldPassword\"></div><div class=\"form-group\"><label>新密码</label><input type=\"password\" id=\"newPassword\"></div><div class=\"form-group\"><label>确认新密码</label><input type=\"password\" id=\"confirmPassword\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"changePassword()\">修改</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pwdModal\\')\">取消</button></div>';showCustomModal('修改密码',html,'pwdModal')}\nfunction changePassword(){var oldPwd=$('oldPassword').value,newPwd=$('newPassword').value,confirmPwd=$('confirmPassword').value;if(!oldPwd||!newPwd){alert('请填写密码');return}if(newPwd!==confirmPwd){alert('两次密码不一致');return}alert('密码修改功能开发中')}\n// 检查 URL 中的 token(OAuth 回调)\n(function(){var params=new URLSearchParams(window.location.search);var token=params.get('token');if(token){localStorage.setItem('token',token);authToken=token;window.history.replaceState({},document.title,'/');checkAuth()}})();\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\n// 代码运行器\nfunction runCode(){var code=$('codeInput').value;var lang=$('codeLanguage').value;if(!code.trim()){alert('请输入代码');return}$('codeOutput').textContent='运行中...';$('codeOutput').style.color='var(--text2)';api('/api/code/run',{method:'POST',body:JSON.stringify({code:code,language:lang,timeout:5})}).then(function(data){if(data.success){$('codeOutput').textContent=data.output||'(无输出)';$('codeOutput').style.color='var(--success)'}else{$('codeOutput').textContent='错误: '+(data.error||'未知错误')+'\\n'+data.output;$('codeOutput').style.color='var(--error)'}}).catch(function(e){$('codeOutput').textContent='请求失败: '+e.message;$('codeOutput').style.color='var(--error)'})}\n// 思维导图\nfunction generateMindmap(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}showToast('正在生成思维导图...');api('/api/mindmap/generate',{method:'POST',body:JSON.stringify({messages:chat.messages,title:chat.title})}).then(function(data){renderMindmap(data.nodes)}).catch(function(e){alert('生成失败: '+e.message)})}\nfunction renderMindmap(nodes){var html='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.8);z-index:2000;display:flex;align-items:center;justify-content:center\" onclick=\"if(event.target===this)this.remove()\"><div style=\"background:var(--bg2);border-radius:16px;padding:24px;max-width:800px;max-height:80vh;overflow:auto\"><h3 style=\"margin-bottom:16px\">🧠 思维导图</h3><div id=\"mindmapContent\" style=\"padding:20px\"></div><button class=\"btn btn-ghost\" onclick=\"this.parentElement.parentElement.remove()\">关闭</button></div></div>';document.body.insertAdjacentHTML('beforeend',html);var content='';function renderNode(node,level){var indent=level*24;content+='<div style=\"margin-left:'+indent+'px;padding:8px 12px;margin-bottom:4px;background:var(--bg'+(level>0?'3':'')+');border-radius:6px;border-left:3px solid var(--accent)\">'+(level>0?'├─ ':'')+node.label+'</div>';if(node.children){node.children.forEach(function(c){renderNode(c,level+1)})}}if(nodes&&nodes.length)renderNode(nodes[0],0);$('mindmapContent').innerHTML=content||'<p style=\"color:var(--text2)\">无法生成思维导图</p>'}\n// 保存对话为模板\nfunction saveAsTemplate(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}var name=prompt('模板名称:',chat.title);if(!name)return;api('/api/chat-templates',{method:'POST',body:JSON.stringify({name:name,messages:chat.messages})}).then(function(){showToast('已保存为模板')}).catch(function(e){alert('保存失败: '+e.message)})}\n// 用量配额\nfunction loadQuota(){api('/api/quota').then(function(data){var html='<div style=\"margin-bottom:16px\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Token 使用量</span><span>'+formatNumber(data.tokens_used)+' / '+formatNumber(data.tokens_limit)+'</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;overflow:hidden\"><div style=\"background:var(--accent);height:100%;width:'+data.usage_percent+'%\"></div></div></div><p style=\"font-size:12px;color:var(--text2)\">当前套餐: '+data.plan+'</p>';if($('quotaInfo'))$('quotaInfo').innerHTML=html}).catch(function(e){console.error(e)})}\n// PWA 注册\nif('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js').then(function(reg){console.log('SW registered');if('Notification' in window&&Notification.permission==='default'){Notification.requestPermission()}}).catch(function(e){console.error('SW failed:',e)})}\n// 图片生成\nfunction generateImage(){var prompt=prompt('输入图片描述:');if(!prompt)return;showToast('正在生成图片...');api('/api/images/generate',{method:'POST',body:JSON.stringify({prompt:prompt})}).then(function(data){var img='<img src=\"'+data.url+'\" style=\"max-width:100%;border-radius:8px\">';var chat=chats.find(function(c){return c.id===currentChatId});if(chat){chat.messages.push({role:'assistant',content:'![生成的图片]('+data.url+')\\n\\n'+data.revised_prompt});saveChats();renderMessages()}showToast('图片已生成')}).catch(function(e){alert('生成失败: '+e.message)})}\n// TTS 语音合成\nfunction speakText(text){api('/api/audio/tts',{method:'POST',body:JSON.stringify({text:text,voice:'alloy'})}).then(function(data){var audio=new Audio(data.audio);audio.play();showToast('正在播放')}).catch(function(e){if('speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(text);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('TTS 失败: '+e.message)}})}\n// 内容过滤\nfunction filterContent(text){return api('/api/content/filter',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data})}\n// 数据脱敏\nfunction maskData(text){return api('/api/data/mask',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data.masked})}\n// 备份\nfunction createBackup(){api('/api/backup',{method:'POST'}).then(function(data){showToast('备份已创建: '+data.path)}).catch(function(e){alert('备份失败: '+e.message)})}\n// 离线检测\nwindow.addEventListener('online',function(){showToast('网络已恢复')});\nwindow.addEventListener('offline',function(){showToast('网络已断开,部分功能不可用')});\n\n// ========== 性能监控面板 ==========\nfunction showHealthDashboard(){\napi('/api/health/detailed').then(function(data){\nvar html='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">CPU 使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.cpu_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.cpu_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">内存使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.memory_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.memory_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">磁盘使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.disk_percent>90?'var(--error)':'var(--success)')+'\">'+data.system.disk_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">数据库延迟</div><div style=\"font-size:24px;font-weight:600;color:'+(data.components.database.latency_ms>100?'var(--warning)':'var(--success)')+'\">'+data.components.database.latency_ms+'ms</div></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:10px\">';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>缓存</span><span>'+data.components.cache.size+'/'+data.components.cache.max_size+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Redis</span><span style=\"color:'+(data.components.redis.status==='healthy'?'var(--success)':'var(--warning)')+'\">'+data.components.redis.status+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between\"><span>待处理任务</span><span>'+data.components.task_queue.pending_tasks+'</span></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;text-align:center;font-size:12px;color:var(--text2)\">版本 '+data.version+' · 运行时间 '+formatUptime(data.uptime_seconds)+'</div>';\nshowCustomModal('🖥️ 系统状态',html,'healthModal')\n}).catch(function(e){alert('获取状态失败: '+e.message)})}\nfunction formatUptime(seconds){var h=Math.floor(seconds/3600);var m=Math.floor((seconds%3600)/60);return h+'小时'+m+'分钟'}\n\n// ========== 批量操作 ==========\nvar batchMode=false;\nvar selectedChats=[];\nfunction toggleBatchMode(){batchMode=!batchMode;selectedChats=[];if(batchMode){$('batchActions').style.display='flex';showToast('已进入批量选择模式')}else{$('batchActions').style.display='none'}renderChatList()}\nfunction toggleChatSelection(id,e){if(!batchMode)return;e.stopPropagation();var idx=selectedChats.indexOf(id);if(idx>=0){selectedChats.splice(idx,1)}else{selectedChats.push(id)}renderChatList();$('selectedCount').textContent=selectedChats.length}\nfunction batchDeleteChats(){if(selectedChats.length===0){alert('请先选择对话');return}if(!confirm('确定删除 '+selectedChats.length+' 个对话?'))return;api('/api/conversations/batch-delete',{method:'POST',body:JSON.stringify({ids:selectedChats})}).then(function(data){showToast('已删除 '+data.deleted+' 个对话');selectedChats=[];batchMode=false;$('batchActions').style.display='none';loadChats()}).catch(function(e){alert('删除失败: '+e.message)})}\nfunction batchExportChats(){if(selectedChats.length===0){alert('请先选择对话');return}api('/api/messages/batch-export',{method:'POST',body:JSON.stringify({conversation_ids:selectedChats,format:'json'})}).then(function(data){var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='conversations_export.json';a.click();showToast('已导出 '+data.count+' 个对话')}).catch(function(e){alert('导出失败: '+e.message)})}\n\n// ========== 数据库优化 ==========\nfunction optimizeDatabase(){if(!confirm('确定要优化数据库?这将清理过期数据。'))return;showToast('正在优化...');api('/api/admin/optimize-db',{method:'POST'}).then(function(data){showToast(data.message)}).catch(function(e){alert('优化失败: '+e.message)})}\n\n// ========== 快捷键增强 ==========\ndocument.addEventListener('keydown',function(e){\nif(e.ctrlKey&&e.key==='h'){e.preventDefault();showHealthDashboard()}\nif(e.ctrlKey&&e.key==='b'){e.preventDefault();toggleBatchMode()}\nif(e.ctrlKey&&e.shiftKey&&e.key==='E'){e.preventDefault();batchExportChats()}\nif(e.ctrlKey&&e.key==='f'){e.preventDefault();searchInCurrentChat()}\nif(e.ctrlKey&&e.key==='/'||e.key==='?'){e.preventDefault();showHotkeyHelp()}\n});\n\n// ========== 性能优化:虚拟滚动 ==========\nfunction renderChatListVirtual(){\nvar container=$('chatList');\nvar itemHeight=60;\nvar visibleCount=Math.ceil(container.clientHeight/itemHeight)+2;\nvar scrollTop=container.scrollTop;\nvar startIndex=Math.floor(scrollTop/itemHeight);\nvar endIndex=Math.min(startIndex+visibleCount,chats.length);\nvar html='<div style=\"height:'+(startIndex*itemHeight)+'px\"></div>';\nfor(var i=startIndex;i<endIndex;i++){\nvar c=chats[i];\nvar active=c.id===currentChatId?'active':'';\nvar selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';\nvar checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';\nhtml+='<div class=\"sidebar-item '+active+'\" style=\"'+selected+'\" onclick=\"loadChat(\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+c.title+'</div><div class=\"sidebar-item-desc\">'+(c.messages.length||0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" style=\"opacity:0\" onclick=\"deleteChat(\\''+c.id+'\\',event)\">🗑️</button></div>'\n}\nhtml+='<div style=\"height:'+((chats.length-endIndex)*itemHeight)+'px\"></div>';\ncontainer.innerHTML=html}\n\n// ========== 请求重试机制 ==========\nasync function apiWithRetry(url,options,maxRetries=3){\nfor(var i=0;i<maxRetries;i++){\ntry{return await api(url,options)}\ncatch(e){\nif(i===maxRetries-1)throw e;\nawait new Promise(function(r){setTimeout(r,1000*(i+1))});\nconsole.log('Retrying request...',i+1)\n}}}\n\n// ========== 消息队列(离线支持) ==========\nvar offlineQueue=JSON.parse(localStorage.getItem('offlineQueue')||'[]');\nfunction queueOfflineMessage(msg){offlineQueue.push({msg:msg,time:Date.now()});localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))}\nfunction processOfflineQueue(){if(offlineQueue.length===0)return;showToast('正在发送离线消息...');var msg=offlineQueue.shift();localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue));sendMessageInternal(msg.msg).then(function(){processOfflineQueue()}).catch(function(){offlineQueue.unshift(msg);localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))})}\nwindow.addEventListener('online',processOfflineQueue);\n\n// ========== 智能预加载 ==========\nfunction preloadNextChat(){\nvar currentIdx=chats.findIndex(function(c){return c.id===currentChatId});\nif(currentIdx>=0&&currentIdx<chats.length-1){\nvar nextChat=chats[currentIdx+1];\nif(!nextChat.messages||nextChat.messages.length===0){\napi('/api/conversations/'+nextChat.id+'/messages').then(function(msgs){nextChat.messages=msgs})}}}\n\n// ========== 自动保存草稿 ==========\nvar draftTimer=null;\nfunction saveDraft(){var input=$('chatInput').value;if(input&&currentChatId){localStorage.setItem('draft_'+currentChatId,input)}}\nfunction loadDraft(){if(currentChatId){var draft=localStorage.getItem('draft_'+currentChatId);if(draft)$('chatInput').value=draft}}\nfunction clearDraft(){if(currentChatId)localStorage.removeItem('draft_'+currentChatId)}\n$('chatInput').addEventListener('input',function(){clearTimeout(draftTimer);draftTimer=setTimeout(saveDraft,1000)});\n\n// ========== 消息搜索增强 ==========\nfunction searchInCurrentChat(){var q=prompt('在当前对话中搜索:');if(!q)return;var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages)return;var results=chat.messages.filter(function(m){return m.content&&m.content.toLowerCase().includes(q.toLowerCase())});if(results.length===0){alert('未找到匹配消息');return}var html='<div style=\"max-height:400px;overflow-y:auto\">';results.forEach(function(m,i){html+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:4px\">'+(m.role==='user'?'👤 用户':'🤖 助手')+'</div><div style=\"font-size:14px\">'+m.content.slice(0,200)+(m.content.length>200?'...':'')+'</div></div>'});html+='</div>';showCustomModal('搜索结果 ('+results.length+')',html,'searchResultModal')}\n\n// ========== 快速回复 ==========\nvar quickReplies=[\n{id:'continue',text:'继续',prompt:'请继续'},\n{id:'explain',text:'解释',prompt:'请详细解释一下'},\n{id:'example',text:'举例',prompt:'请举个例子'},\n{id:'simplify',text:'简化',prompt:'请用更简单的语言解释'},\n{id:'code',text:'代码',prompt:'请给出代码示例'},\n{id:'summary',text:'总结',prompt:'请总结一下要点'}\n];\nfunction showQuickReplies(){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages||chat.messages.length===0){$('quickReplies').style.display='none';return}\nvar lastMsg=chat.messages[chat.messages.length-1];\nif(lastMsg.role!=='assistant'){$('quickReplies').style.display='none';return}\nvar html=quickReplies.map(function(r){return'<button class=\"btn btn-ghost btn-sm\" onclick=\"sendQuickReply(\\''+r.prompt+'\\')\">'+r.text+'</button>'}).join('');\n$('quickReplies').innerHTML=html;\n$('quickReplies').style.display='flex'}\nfunction sendQuickReply(prompt){$('chatInput').value=prompt;sendMessage()}\n\n// ========== 数据导入导出 ==========\nfunction exportAllData(){\nif(!authToken){alert('请先登录');return}\nshowToast('正在导出数据...');\napi('/api/data/export-all',{method:'POST'}).then(function(data){\nvar blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='ai_hub_backup_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})}\n\nfunction importAllData(){\nif(!authToken){alert('请先登录');return}\nvar input=document.createElement('input');\ninput.type='file';\ninput.accept='.json';\ninput.onchange=function(e){\nvar file=e.target.files[0];\nif(!file)return;\nvar reader=new FileReader();\nreader.onload=function(ev){\ntry{\nvar data=JSON.parse(ev.target.result);\nif(!confirm('确定要导入数据?这将添加 '+\n(data.conversations?data.conversations.length:0)+' 个对话、'+\n(data.notes?data.notes.length:0)+' 个笔记'))return;\napi('/api/data/import',{method:'POST',body:JSON.stringify(data)}).then(function(result){\nshowToast('导入完成: '+result.imported.conversations+' 对话, '+result.imported.notes+' 笔记');\nloadChats()\n}).catch(function(e){alert('导入失败: '+e.message)})\n}catch(e){alert('文件格式错误')}};\nreader.readAsText(file)};\ninput.click()}\n\n// ========== 智能推荐 ==========\nfunction loadRecommendations(){\napi('/api/recommendations').then(function(data){\nif(data.features&&data.features.length>0){\nvar html='<div style=\"padding:16px;background:var(--bg3);border-radius:10px;margin-bottom:16px\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:12px\">💡 推荐功能</div><div style=\"display:flex;gap:12px;flex-wrap:wrap\">';\ndata.features.forEach(function(f){\nhtml+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;cursor:pointer;flex:1;min-width:150px\" onclick=\"showFeatureGuide(\\''+f.name+'\\')\"><span style=\"font-size:20px\">'+f.icon+'</span><div style=\"font-size:14px;font-weight:500;margin-top:8px\">'+f.name+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+f.desc+'</div></div>'});\nhtml+='</div></div>';\nvar container=$('chatMessages');\nif(container&&container.querySelector('.empty-state')){\ncontainer.innerHTML=html+container.innerHTML}}\n}).catch(function(){})}\nfunction showFeatureGuide(name){\nvar guides={\n'知识库':'点击左侧导航的\"知识库\",创建知识库并上传文档,AI 将基于您的资料回答问题。',\n'团队协作':'点击左侧导航的\"团队空间\",创建团队并邀请成员,共享对话和资源。'\n};\nalert(guides[name]||'功能介绍开发中')}\n\n// ========== 收藏消息 ==========\nfunction favoriteMessage(content){\nif(!authToken){alert('请先登录');return}\napi('/api/messages/favorite',{method:'POST',body:JSON.stringify({\nconversation_id:currentChatId,\ncontent:content\n})}).then(function(){showToast('已收藏到记忆')}).catch(function(e){alert('收藏失败: '+e.message)})}\nfunction favoriteMessageByIndex(index){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages[index])return;\nfavoriteMessage(chat.messages[index].content)}\n\n// ========== 使用分析 ==========\nfunction showUsageAnalytics(){\napi('/api/analytics/usage?days=30').then(function(data){\nvar html='<div style=\"margin-bottom:20px\"><h4 style=\"margin-bottom:12px\">📊 30天使用趋势</h4>';\nif(data.daily_usage.length>0){\nvar maxCalls=Math.max.apply(null,data.daily_usage.map(function(d){return d.calls}));\nhtml+='<div style=\"display:flex;align-items:flex-end;gap:4px;height:100px\">';\ndata.daily_usage.forEach(function(d){\nvar height=Math.max(5,(d.calls/maxCalls)*100);\nhtml+='<div style=\"flex:1;background:var(--accent);border-radius:2px 2px 0 0;height:'+height+'px\" title=\"'+d.day+': '+d.calls+'次\"></div>'});\nhtml+='</div>'}\nhtml+='</div>';\nhtml+='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">总调用次数</div><div style=\"font-size:24px;font-weight:600\">'+data.total_calls+'</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">错误率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.error_rate>5?'var(--error)':'var(--success)')+'\">'+data.error_rate+'%</div></div>';\nhtml+='</div>';\nshowCustomModal('📈 使用分析',html,'analyticsModal')\n}).catch(function(e){alert('获取分析失败: '+e.message)})}\n\n// ========== 第三方集成 ==========\nfunction saveIntegration(type){\nvar data={};\nif(type==='slack'){\ndata={slack_token:$('slackToken').value,slack_secret:$('slackSecret').value}\n}else if(type==='feishu'){\ndata={feishu_app_id:$('feishuAppId').value,feishu_secret:$('feishuSecret').value}\n}else if(type==='webhook'){\ndata={webhook_url:$('webhookUrl').value,webhook_new_msg:$('webhookNewMsg').checked,webhook_error:$('webhookError').checked}\n}\nlocalStorage.setItem('integration_'+type,JSON.stringify(data));\nshowToast('配置已保存')}\n\nfunction loadIntegrations(){\ntry{\nvar slack=JSON.parse(localStorage.getItem('integration_slack')||'{}');\nif(slack.slack_token)$('slackToken').value=slack.slack_token;\nif(slack.slack_secret)$('slackSecret').value=slack.slack_secret;\nvar feishu=JSON.parse(localStorage.getItem('integration_feishu')||'{}');\nif(feishu.feishu_app_id)$('feishuAppId').value=feishu.feishu_app_id;\nif(feishu.feishu_secret)$('feishuSecret').value=feishu.feishu_secret;\nvar webhook=JSON.parse(localStorage.getItem('integration_webhook')||'{}');\nif(webhook.webhook_url)$('webhookUrl').value=webhook.webhook_url;\nif(webhook.webhook_new_msg)$('webhookNewMsg').checked=true;\nif(webhook.webhook_error)$('webhookError').checked=true;\n}catch(e){}}\n\nfunction testSlackIntegration(){\nshowToast('测试 Slack 连接...');\napi('/api/integrations/slack/send',{method:'POST',body:JSON.stringify({channel:'#general',text:'AI Hub 测试消息'})}).then(function(data){\nif(data.ok){showToast('Slack 连接成功!')}else{alert('连接失败: '+(data.error||'未知错误'))}\n}).catch(function(e){alert('连接失败: '+e.message)})}\n\nfunction testFeishuIntegration(){\nshowToast('测试飞书连接...');\napi('/api/integrations/feishu/send',{method:'POST',body:JSON.stringify({chat_id:'test',text:'AI Hub 测试消息'})}).then(function(data){\nif(data.code===0){showToast('飞书连接成功!')}else{alert('连接失败: '+(data.msg||'未知错误'))}\n}).catch(function(e){alert('连接失败: '+e.message)})}\n\n// ========== 灰度发布 ==========\nfunction loadFeatureFlags(){\napi('/api/features/all').then(function(data){\nvar html='';\nfor(var name in data){\nvar flag=data[name];\nhtml+='<div style=\"display:flex;justify-content:space-between;align-items:center;padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\">';\nhtml+='<div><strong>'+name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">灰度比例: '+flag.percentage+'% · 白名单用户: '+(flag.users?flag.users.length:0)+'</div></div>';\nhtml+='<label class=\"switch\"><input type=\"checkbox\" '+(flag.enabled?'checked':'')+' onchange=\"toggleFeatureFlag(\\''+name+'\\',this.checked)\"><span class=\"switch-slider\"></span></label>';\nhtml+='</div>'}\n$('featureFlagsList').innerHTML=html||'<p style=\"color:var(--text2)\">暂无功能开关</p>'\n}).catch(function(e){$('featureFlagsList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction toggleFeatureFlag(name,enabled){\napi('/api/features/'+name,{method:'POST',body:JSON.stringify({enabled:enabled})}).then(function(){\nshowToast(name+(enabled?' 已启用':' 已禁用'))\n}).catch(function(e){alert('操作失败: '+e.message)})}\n\nfunction updateFeatureFlagPercentage(name,percentage){\napi('/api/features/'+name,{method:'POST',body:JSON.stringify({percentage:parseInt(percentage)})}).then(function(){\nshowToast('灰度比例已更新')\n}).catch(function(e){alert('操作失败: '+e.message)})}\n\n// ========== 链路追踪 ==========\nfunction loadTraces(){\napi('/api/traces?limit=50').then(function(data){\nif(data.length===0){$('tracesList').innerHTML='<p style=\"color:var(--text2)\">暂无追踪记录</p>';return}\nvar html='<table style=\"width:100%;border-collapse:collapse;font-size:13px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">ID</th><th style=\"padding:10px\">名称</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">Spans</th></tr>';\ndata.forEach(function(t){\nhtml+='<tr style=\"border-top:1px solid var(--border);cursor:pointer\" onclick=\"showTraceDetail(\\''+t.id+'\\')\">';\nhtml+='<td style=\"padding:10px;font-family:monospace\">'+t.id+'</td>';\nhtml+='<td style=\"padding:10px\">'+t.name+'</td>';\nhtml+='<td style=\"padding:10px;text-align:right\">'+(t.total_duration?(t.total_duration*1000).toFixed(0)+'ms':'-')+'</td>';\nhtml+='<td style=\"padding:10px\">'+(t.spans?t.spans.length:0)+'</td>';\nhtml+='</tr>'});\nhtml+='</table>';\n$('tracesList').innerHTML=html\n}).catch(function(e){$('tracesList').innerHTML='<p style=\"color:var(--error)\">加载失败</p>'})}\n\nfunction showTraceDetail(traceId){\napi('/api/traces/'+traceId).then(function(data){\nvar html='<div style=\"margin-bottom:16px\"><strong>Trace ID:</strong> '+data.id+'<br><strong>名称:</strong> '+data.name+'<br><strong>总耗时:</strong> '+(data.total_duration?(data.total_duration*1000).toFixed(0)+'ms':'-')+'</div>';\nif(data.spans&&data.spans.length>0){\nhtml+='<h4 style=\"margin-bottom:12px\">Spans</h4>';\ndata.spans.forEach(function(s,i){\nvar width=Math.min(100,s.duration*100);\nhtml+='<div style=\"margin-bottom:8px\"><div style=\"display:flex;justify-content:space-between;font-size:13px\"><span>'+s.name+'</span><span>'+(s.duration*1000).toFixed(0)+'ms</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;margin-top:4px\"><div style=\"background:var(--accent);height:100%;width:'+width+'%;border-radius:4px\"></div></div></div>'\n})}\nshowCustomModal('🔍 追踪详情',html,'traceDetailModal')\n}).catch(function(e){alert('加载失败: '+e.message)})}\n\nfunction exportTraces(){\napi('/api/traces?limit=100').then(function(data){\nif(data.length===0){alert('暂无追踪记录');return}\nvar traceIds=data.map(function(t){return t.id});\napi('/api/traces/export',{method:'POST',body:JSON.stringify({trace_ids:traceIds,format:'jaeger'})}).then(function(result){\nvar blob=new Blob([JSON.stringify(result.data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='traces_export_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('追踪数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})\n}).catch(function(e){alert('获取追踪失败: '+e.message)})}\n\n// 初始化时加载推荐\nsetTimeout(loadRecommendations,1000);\nsetTimeout(loadIntegrations,100);\n\n// ========== 快捷键帮助 ==========\nfunction showHotkeyHelp(){\nvar html='<div style=\"display:grid;gap:8px\">';\nvar hotkeys=[\n['Ctrl + N','新建对话'],\n['Ctrl + K','全局搜索'],\n['Ctrl + D','切换主题'],\n['Ctrl + H','系统状态'],\n['Ctrl + B','批量选择'],\n['Ctrl + F','搜索当前对话'],\n['Ctrl + /','快捷键帮助'],\n['Enter','发送消息'],\n['Shift + Enter','换行'],\n['Escape','关闭弹窗']\n];\nhotkeys.forEach(function(h){\nhtml+='<div class=\"hotkey-help-item\"><span>'+h[1]+'</span><span class=\"hotkey-help-key\">'+h[0]+'</span></div>'\n});\nhtml+='</div>';\nshowCustomModal('⌨️ 快捷键帮助',html,'hotkeyHelpModal')}\n\n// ========== 欢迎引导 ==========\nfunction showWelcomeGuide(){\nif(localStorage.getItem('welcomeShown'))return;\nvar html='<div style=\"text-align:center;padding:20px\"><div style=\"font-size:48px;margin-bottom:16px\">🤖</div><h2 style=\"margin-bottom:12px\">欢迎使用 AI Hub</h2><p style=\"color:var(--text2);margin-bottom:24px\">一站式 AI 平台,支持多模型、多功能</p><div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:12px;text-align:left;margin-bottom:24px\"><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">💬</span><div style=\"font-weight:500;margin-top:8px\">多模型对话</div><div style=\"font-size:12px;color:var(--text2)\">支持 OpenAI、Claude、Gemini 等</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">🎨</span><div style=\"font-weight:500;margin-top:8px\">图片生成</div><div style=\"font-size:12px;color:var(--text2)\">DALL-E 3 AI 绘图</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">📚</span><div style=\"font-weight:500;margin-top:8px\">知识库</div><div style=\"font-size:12px;color:var(--text2)\">上传文档,智能问答</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">👥</span><div style=\"font-weight:500;margin-top:8px\">团队协作</div><div style=\"font-size:12px;color:var(--text2)\">多人共享对话和资源</div></div></div><button class=\"btn btn-primary\" onclick=\"closeModal(\\'welcomeModal\\');localStorage.setItem(\\'welcomeShown\\',\\'1\\')\">开始使用</button></div>';\nshowCustomModal('',html,'welcomeModal')}\nsetTimeout(showWelcomeGuide,500);\n\nconsole.log('🤖 AI Hub v2.0.0 - Enhanced');\n</script>\n</body>\n</html>\n"}, "72330c39fe5147177f5fceb11976e88f3726d2bb": {"t": 1785765465.754782, "n": 209920, "h": "7244f51bb0d5379e", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"theme-color\" content=\"#0f0f1a\">\n<meta name=\"description\" content=\"AI Hub - 统一 AI 平台\">\n<link rel=\"manifest\" href=\"/static/manifest.json\">\n<link rel=\"apple-touch-icon\" href=\"/static/icon-192.png\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"workflows\"><span class=\"nav-item-icon\">🤖</span> Agent 工作流</div>\n<div class=\"nav-item\" data-page=\"code-runner\"><span class=\"nav-item-icon\">▶️</span> 代码运行</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" onclick=\"showHealthDashboard()\"><span class=\"nav-item-icon\">🖥️</span> 系统状态</div>\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\" title=\"批量操作\">☑️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div id=\"batchActions\" style=\"display:none;padding:8px;background:var(--bg3);gap:8px;align-items:center\">\n<span style=\"font-size:12px\">已选 <span id=\"selectedCount\">0</span> 个</span>\n<button class=\"btn btn-danger btn-sm\" onclick=\"batchDeleteChats()\">删除</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"batchExportChats()\">导出</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\">取消</button>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"quickReplies\" style=\"display:none;padding:8px 0;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap\"></div>\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateImage()\" title=\"生成图片\">🎨</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateMindmap()\" title=\"生成思维导图\">🧠</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"saveAsTemplate()\" title=\"保存为模板\">💾</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">双因素认证 (2FA)<br><small style=\"color:var(--text2)\">使用 Google Authenticator 等应用增强账户安全</small></div><div style=\"display:flex;gap:8px\"><span id=\"2faStatus\" style=\"color:var(--text2)\">未启用</span><button class=\"btn btn-ghost btn-sm\" onclick=\"setup2FA()\" id=\"2faBtn\">设置</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录设备管理</div><button class=\"btn btn-ghost btn-sm\" onclick=\"alert('功能开发中')\">查看设备</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">修改密码</div><button class=\"btn btn-ghost btn-sm\" onclick=\"showChangePasswordModal()\">修改</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复<br><small style=\"color:var(--text2)\">导出/导入所有数据(对话、笔记、记忆、设置)</small></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-primary\" onclick=\"exportAllData()\">📤 导出全部</button><button class=\"btn btn-ghost\" onclick=\"importAllData()\">📥 导入数据</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据库优化<br><small style=\"color:var(--text2)\">清理过期数据,优化数据库性能</small></div><button class=\"btn btn-ghost\" onclick=\"optimizeDatabase()\">🔧 优化数据库</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n<button class=\"btn btn-primary\" onclick=\"showUsageAnalytics()\">📈 详细分析</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Agent 工作流页 -->\n<div id=\"page-workflows\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🤖</span> Agent 工作流</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建多步骤自动化任务,让 AI 按流程完成复杂工作</p>\n<div id=\"workflowTemplates\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px\"></div>\n</div>\n<div class=\"settings-section\" id=\"workflowRunner\" style=\"display:none\">\n<h4><span>▶️</span> 运行工作流</h4>\n<div id=\"workflowInputs\"></div>\n<button class=\"btn btn-primary\" onclick=\"executeWorkflow()\">🚀 执行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('workflowRunner').style.display='none'\">取消</button>\n</div>\n<div class=\"settings-section\" id=\"workflowResults\" style=\"display:none\">\n<h4><span>📋</span> 执行结果</h4>\n<div id=\"workflowResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 代码运行器页 -->\n<div id=\"page-code-runner\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>▶️</span> 代码运行器</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">在线运行 Python / JavaScript 代码</p>\n<div class=\"form-group\">\n<label>语言</label>\n<select id=\"codeLanguage\" style=\"width:150px\">\n<option value=\"python\">Python</option>\n<option value=\"javascript\">JavaScript</option>\n</select>\n</div>\n<div class=\"form-group\">\n<label>代码</label>\n<textarea id=\"codeInput\" rows=\"12\" style=\"font-family:monospace;font-size:13px\" placeholder=\"# 输入代码...\nprint('Hello, World!')\"></textarea>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-primary\" onclick=\"runCode()\">▶️ 运行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('codeInput').value=''\">清空</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 输出结果</h4>\n<pre id=\"codeOutput\" style=\"background:var(--bg);padding:16px;border-radius:8px;min-height:100px;font-family:monospace;font-size:13px;white-space:pre-wrap\">等待运行...</pre>\n</div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>系统状态</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + H</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量选择模式</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + B</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量导出</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>搜索当前对话</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + F</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换主题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + D</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><div class=\"form-group\" id=\"auth2FAGroup\" style=\"display:none\"><label>2FA 验证码</label><input type=\"text\" id=\"auth2FACode\" placeholder=\"6位验证码\" maxlength=\"6\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><div style=\"display:flex;align-items:center;margin:16px 0\"><div style=\"flex:1;height:1px;background:var(--border)\"></div><span style=\"padding:0 12px;color:var(--text2);font-size:12px\">或</span><div style=\"flex:1;height:1px;background:var(--border)\"></div></div><button class=\"btn btn-ghost\" style=\"width:100%;display:flex;align-items:center;justify-content:center;gap:8px\" onclick=\"loginWithGithub()\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg> 使用 GitHub 登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();if(n.dataset.page==='workflows')loadWorkflowTemplates();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{\n// 先显示置顶的对话\nvar pinnedChats=chats.filter(function(c){return c.pinned});\nvar normalChats=chats.filter(function(c){return !c.pinned&&!c.archived});\nif(pinnedChats.length>0){html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2)\">📌 置顶</div>';pinnedChats.forEach(function(c){html+=renderChatItem(c)})}\nif(normalChats.length>0){if(pinnedChats.length>0)html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2);margin-top:8px\">💬 对话</div>';normalChats.forEach(function(c){html+=renderChatItem(c)})}}$('chatList').innerHTML=html}\nfunction renderChatItem(c){var selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';var checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';var pinIcon=c.pinned?'📌':'💬';return'<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" style=\"'+selected+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">'+pinIcon+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"favoriteMessageByIndex('+i+')\" title=\"收藏\">❤️</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll();showQuickReplies()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var chat=chats.find(function(c){return c.id===id});var pinText=chat&&chat.pinned?'📌 取消置顶':'📌 置顶';var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"togglePinChat(\\''+id+'\\')\">'+pinText+'</div><div onclick=\"archiveChat(\\''+id+'\\')\">📦 归档</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction togglePinChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.pinned=!chat.pinned;saveChats();renderChats();showToast(chat.pinned?'已置顶':'已取消置顶');if(authToken){api('/api/conversations/'+id+'/pin',{method:'POST'}).catch(function(){})}}\nfunction archiveChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.archived=true;chats=chats.filter(function(c){return c.id!==id});saveChats();renderChats();showToast('已归档');if(authToken){api('/api/conversations/'+id+'/archive',{method:'POST'}).catch(function(){})}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Agent 工作流\nvar workflowTemplates=[];\nvar currentWorkflow=null;\nfunction loadWorkflowTemplates(){api('/api/workflows/templates').then(function(data){workflowTemplates=data;renderWorkflowTemplates()}).catch(function(e){console.error('加载工作流失败:',e)})}\nfunction renderWorkflowTemplates(){var html=workflowTemplates.map(function(w){return'<div style=\"background:var(--bg);border-radius:12px;padding:20px;cursor:pointer\" onclick=\"selectWorkflow(\\''+w.id+'\\')\"><div style=\"display:flex;align-items:center;gap:12px;margin-bottom:12px\"><span style=\"font-size:24px\">🤖</span><div><strong>'+w.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+w.steps.length+' 个步骤</div></div></div><p style=\"font-size:13px;color:var(--text2);line-height:1.5\">'+w.description+'</p></div>'}).join('');$('workflowTemplates').innerHTML=html||'<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无工作流模板</div>'}\nfunction selectWorkflow(id){currentWorkflow=workflowTemplates.find(function(w){return w.id===id});if(!currentWorkflow)return;var inputs=[];currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')&&inputs.indexOf(key)===-1)inputs.push(key)})}});var html=inputs.map(function(key){return'<div class=\"form-group\"><label>'+key+'</label><textarea id=\"wf_'+key+'\" rows=\"3\" placeholder=\"输入 '+key+'\"></textarea></div>'}).join('');$('workflowInputs').innerHTML='<h5 style=\"margin-bottom:16px\">'+currentWorkflow.name+'</h5>'+html;$('workflowRunner').style.display='block';$('workflowResults').style.display='none'}\nfunction executeWorkflow(){if(!currentWorkflow){alert('请先选择工作流');return}var inputData={};currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')){var el=$('wf_'+key);if(el)inputData[key]=el.value}})}});$('workflowResultsContent').innerHTML='<div style=\"text-align:center;padding:40px\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px;color:var(--text2)\">正在执行工作流...</p></div>';$('workflowResults').style.display='block';api('/api/workflows/run',{method:'POST',body:JSON.stringify({name:currentWorkflow.name,steps:currentWorkflow.steps,input_data:inputData})}).then(function(data){var html='';for(var key in data.results){html+='<div style=\"background:var(--bg);border-radius:10px;padding:16px;margin-bottom:12px\"><div style=\"font-weight:600;margin-bottom:8px;color:var(--accent)\">'+key+'</div><div style=\"font-size:14px;line-height:1.6;white-space:pre-wrap\">'+data.results[key]+'</div></div>'}$('workflowResultsContent').innerHTML=html}).catch(function(e){$('workflowResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">执行失败: '+e.message+'</div>'})}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// GitHub 登录\nfunction loginWithGithub(){window.location.href='/api/auth/github'}\n// 2FA 设置\nfunction setup2FA(){if(!authToken){alert('请先登录');return}api('/api/auth/2fa/setup',{method:'POST'}).then(function(data){var html='<div style=\"text-align:center\"><img src=\"'+data.qr_code+'\" style=\"width:200px;height:200px;border-radius:8px\"><p style=\"margin:16px 0;color:var(--text2);font-size:13px\">使用 Google Authenticator 扫描二维码</p><div class=\"form-group\"><label>输入6位验证码确认</label><input type=\"text\" id=\"verify2FACode\" placeholder=\"000000\" maxlength=\"6\" style=\"text-align:center;font-size:20px;letter-spacing:8px\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"verify2FA()\">确认启用</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'2faModal\\')\">取消</button></div></div>';showCustomModal('设置双因素认证',html,'2faModal')}).catch(function(e){alert('设置失败: '+e.message)})}\nfunction verify2FA(){var code=$('verify2FACode').value.trim();if(code.length!==6){alert('请输入6位验证码');return}api('/api/auth/2fa/verify',{method:'POST',body:JSON.stringify({code:code})}).then(function(data){closeModal('2faModal');$('2faStatus').textContent='已启用';$('2faStatus').style.color='var(--success)';$('2faBtn').textContent='禁用';$('2faBtn').onclick=disable2FA;showToast('2FA 已启用')}).catch(function(e){alert('验证失败: '+e.message)})}\nfunction disable2FA(){var code=prompt('输入6位验证码以禁用 2FA:');if(!code)return;api('/api/auth/2fa/disable',{method:'POST',body:JSON.stringify({code:code})}).then(function(){$('2faStatus').textContent='未启用';$('2faStatus').style.color='var(--text2)';$('2faBtn').textContent='设置';$('2faBtn').onclick=setup2FA;showToast('2FA 已禁用')}).catch(function(e){alert('禁用失败: '+e.message)})}\nfunction showChangePasswordModal(){var html='<div class=\"form-group\"><label>当前密码</label><input type=\"password\" id=\"oldPassword\"></div><div class=\"form-group\"><label>新密码</label><input type=\"password\" id=\"newPassword\"></div><div class=\"form-group\"><label>确认新密码</label><input type=\"password\" id=\"confirmPassword\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"changePassword()\">修改</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pwdModal\\')\">取消</button></div>';showCustomModal('修改密码',html,'pwdModal')}\nfunction changePassword(){var oldPwd=$('oldPassword').value,newPwd=$('newPassword').value,confirmPwd=$('confirmPassword').value;if(!oldPwd||!newPwd){alert('请填写密码');return}if(newPwd!==confirmPwd){alert('两次密码不一致');return}alert('密码修改功能开发中')}\n// 检查 URL 中的 token(OAuth 回调)\n(function(){var params=new URLSearchParams(window.location.search);var token=params.get('token');if(token){localStorage.setItem('token',token);authToken=token;window.history.replaceState({},document.title,'/');checkAuth()}})();\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\n// 代码运行器\nfunction runCode(){var code=$('codeInput').value;var lang=$('codeLanguage').value;if(!code.trim()){alert('请输入代码');return}$('codeOutput').textContent='运行中...';$('codeOutput').style.color='var(--text2)';api('/api/code/run',{method:'POST',body:JSON.stringify({code:code,language:lang,timeout:5})}).then(function(data){if(data.success){$('codeOutput').textContent=data.output||'(无输出)';$('codeOutput').style.color='var(--success)'}else{$('codeOutput').textContent='错误: '+(data.error||'未知错误')+'\\n'+data.output;$('codeOutput').style.color='var(--error)'}}).catch(function(e){$('codeOutput').textContent='请求失败: '+e.message;$('codeOutput').style.color='var(--error)'})}\n// 思维导图\nfunction generateMindmap(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}showToast('正在生成思维导图...');api('/api/mindmap/generate',{method:'POST',body:JSON.stringify({messages:chat.messages,title:chat.title})}).then(function(data){renderMindmap(data.nodes)}).catch(function(e){alert('生成失败: '+e.message)})}\nfunction renderMindmap(nodes){var html='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.8);z-index:2000;display:flex;align-items:center;justify-content:center\" onclick=\"if(event.target===this)this.remove()\"><div style=\"background:var(--bg2);border-radius:16px;padding:24px;max-width:800px;max-height:80vh;overflow:auto\"><h3 style=\"margin-bottom:16px\">🧠 思维导图</h3><div id=\"mindmapContent\" style=\"padding:20px\"></div><button class=\"btn btn-ghost\" onclick=\"this.parentElement.parentElement.remove()\">关闭</button></div></div>';document.body.insertAdjacentHTML('beforeend',html);var content='';function renderNode(node,level){var indent=level*24;content+='<div style=\"margin-left:'+indent+'px;padding:8px 12px;margin-bottom:4px;background:var(--bg'+(level>0?'3':'')+');border-radius:6px;border-left:3px solid var(--accent)\">'+(level>0?'├─ ':'')+node.label+'</div>';if(node.children){node.children.forEach(function(c){renderNode(c,level+1)})}}if(nodes&&nodes.length)renderNode(nodes[0],0);$('mindmapContent').innerHTML=content||'<p style=\"color:var(--text2)\">无法生成思维导图</p>'}\n// 保存对话为模板\nfunction saveAsTemplate(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}var name=prompt('模板名称:',chat.title);if(!name)return;api('/api/chat-templates',{method:'POST',body:JSON.stringify({name:name,messages:chat.messages})}).then(function(){showToast('已保存为模板')}).catch(function(e){alert('保存失败: '+e.message)})}\n// 用量配额\nfunction loadQuota(){api('/api/quota').then(function(data){var html='<div style=\"margin-bottom:16px\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Token 使用量</span><span>'+formatNumber(data.tokens_used)+' / '+formatNumber(data.tokens_limit)+'</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;overflow:hidden\"><div style=\"background:var(--accent);height:100%;width:'+data.usage_percent+'%\"></div></div></div><p style=\"font-size:12px;color:var(--text2)\">当前套餐: '+data.plan+'</p>';if($('quotaInfo'))$('quotaInfo').innerHTML=html}).catch(function(e){console.error(e)})}\n// PWA 注册\nif('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js').then(function(reg){console.log('SW registered');if('Notification' in window&&Notification.permission==='default'){Notification.requestPermission()}}).catch(function(e){console.error('SW failed:',e)})}\n// 图片生成\nfunction generateImage(){var prompt=prompt('输入图片描述:');if(!prompt)return;showToast('正在生成图片...');api('/api/images/generate',{method:'POST',body:JSON.stringify({prompt:prompt})}).then(function(data){var img='<img src=\"'+data.url+'\" style=\"max-width:100%;border-radius:8px\">';var chat=chats.find(function(c){return c.id===currentChatId});if(chat){chat.messages.push({role:'assistant',content:'![生成的图片]('+data.url+')\\n\\n'+data.revised_prompt});saveChats();renderMessages()}showToast('图片已生成')}).catch(function(e){alert('生成失败: '+e.message)})}\n// TTS 语音合成\nfunction speakText(text){api('/api/audio/tts',{method:'POST',body:JSON.stringify({text:text,voice:'alloy'})}).then(function(data){var audio=new Audio(data.audio);audio.play();showToast('正在播放')}).catch(function(e){if('speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(text);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('TTS 失败: '+e.message)}})}\n// 内容过滤\nfunction filterContent(text){return api('/api/content/filter',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data})}\n// 数据脱敏\nfunction maskData(text){return api('/api/data/mask',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data.masked})}\n// 备份\nfunction createBackup(){api('/api/backup',{method:'POST'}).then(function(data){showToast('备份已创建: '+data.path)}).catch(function(e){alert('备份失败: '+e.message)})}\n// 离线检测\nwindow.addEventListener('online',function(){showToast('网络已恢复')});\nwindow.addEventListener('offline',function(){showToast('网络已断开,部分功能不可用')});\n\n// ========== 性能监控面板 ==========\nfunction showHealthDashboard(){\napi('/api/health/detailed').then(function(data){\nvar html='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">CPU 使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.cpu_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.cpu_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">内存使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.memory_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.memory_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">磁盘使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.disk_percent>90?'var(--error)':'var(--success)')+'\">'+data.system.disk_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">数据库延迟</div><div style=\"font-size:24px;font-weight:600;color:'+(data.components.database.latency_ms>100?'var(--warning)':'var(--success)')+'\">'+data.components.database.latency_ms+'ms</div></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:10px\">';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>缓存</span><span>'+data.components.cache.size+'/'+data.components.cache.max_size+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Redis</span><span style=\"color:'+(data.components.redis.status==='healthy'?'var(--success)':'var(--warning)')+'\">'+data.components.redis.status+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between\"><span>待处理任务</span><span>'+data.components.task_queue.pending_tasks+'</span></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;text-align:center;font-size:12px;color:var(--text2)\">版本 '+data.version+' · 运行时间 '+formatUptime(data.uptime_seconds)+'</div>';\nshowCustomModal('🖥️ 系统状态',html,'healthModal')\n}).catch(function(e){alert('获取状态失败: '+e.message)})}\nfunction formatUptime(seconds){var h=Math.floor(seconds/3600);var m=Math.floor((seconds%3600)/60);return h+'小时'+m+'分钟'}\n\n// ========== 批量操作 ==========\nvar batchMode=false;\nvar selectedChats=[];\nfunction toggleBatchMode(){batchMode=!batchMode;selectedChats=[];if(batchMode){$('batchActions').style.display='flex';showToast('已进入批量选择模式')}else{$('batchActions').style.display='none'}renderChatList()}\nfunction toggleChatSelection(id,e){if(!batchMode)return;e.stopPropagation();var idx=selectedChats.indexOf(id);if(idx>=0){selectedChats.splice(idx,1)}else{selectedChats.push(id)}renderChatList();$('selectedCount').textContent=selectedChats.length}\nfunction batchDeleteChats(){if(selectedChats.length===0){alert('请先选择对话');return}if(!confirm('确定删除 '+selectedChats.length+' 个对话?'))return;api('/api/conversations/batch-delete',{method:'POST',body:JSON.stringify({ids:selectedChats})}).then(function(data){showToast('已删除 '+data.deleted+' 个对话');selectedChats=[];batchMode=false;$('batchActions').style.display='none';loadChats()}).catch(function(e){alert('删除失败: '+e.message)})}\nfunction batchExportChats(){if(selectedChats.length===0){alert('请先选择对话');return}api('/api/messages/batch-export',{method:'POST',body:JSON.stringify({conversation_ids:selectedChats,format:'json'})}).then(function(data){var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='conversations_export.json';a.click();showToast('已导出 '+data.count+' 个对话')}).catch(function(e){alert('导出失败: '+e.message)})}\n\n// ========== 数据库优化 ==========\nfunction optimizeDatabase(){if(!confirm('确定要优化数据库?这将清理过期数据。'))return;showToast('正在优化...');api('/api/admin/optimize-db',{method:'POST'}).then(function(data){showToast(data.message)}).catch(function(e){alert('优化失败: '+e.message)})}\n\n// ========== 快捷键增强 ==========\ndocument.addEventListener('keydown',function(e){\nif(e.ctrlKey&&e.key==='h'){e.preventDefault();showHealthDashboard()}\nif(e.ctrlKey&&e.key==='b'){e.preventDefault();toggleBatchMode()}\nif(e.ctrlKey&&e.shiftKey&&e.key==='E'){e.preventDefault();batchExportChats()}\nif(e.ctrlKey&&e.key==='f'){e.preventDefault();searchInCurrentChat()}\nif(e.ctrlKey&&e.key==='/'||e.key==='?'){e.preventDefault();showHotkeyHelp()}\n});\n\n// ========== 性能优化:虚拟滚动 ==========\nfunction renderChatListVirtual(){\nvar container=$('chatList');\nvar itemHeight=60;\nvar visibleCount=Math.ceil(container.clientHeight/itemHeight)+2;\nvar scrollTop=container.scrollTop;\nvar startIndex=Math.floor(scrollTop/itemHeight);\nvar endIndex=Math.min(startIndex+visibleCount,chats.length);\nvar html='<div style=\"height:'+(startIndex*itemHeight)+'px\"></div>';\nfor(var i=startIndex;i<endIndex;i++){\nvar c=chats[i];\nvar active=c.id===currentChatId?'active':'';\nvar selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';\nvar checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';\nhtml+='<div class=\"sidebar-item '+active+'\" style=\"'+selected+'\" onclick=\"loadChat(\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+c.title+'</div><div class=\"sidebar-item-desc\">'+(c.messages.length||0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" style=\"opacity:0\" onclick=\"deleteChat(\\''+c.id+'\\',event)\">🗑️</button></div>'\n}\nhtml+='<div style=\"height:'+((chats.length-endIndex)*itemHeight)+'px\"></div>';\ncontainer.innerHTML=html}\n\n// ========== 请求重试机制 ==========\nasync function apiWithRetry(url,options,maxRetries=3){\nfor(var i=0;i<maxRetries;i++){\ntry{return await api(url,options)}\ncatch(e){\nif(i===maxRetries-1)throw e;\nawait new Promise(function(r){setTimeout(r,1000*(i+1))});\nconsole.log('Retrying request...',i+1)\n}}}\n\n// ========== 消息队列(离线支持) ==========\nvar offlineQueue=JSON.parse(localStorage.getItem('offlineQueue')||'[]');\nfunction queueOfflineMessage(msg){offlineQueue.push({msg:msg,time:Date.now()});localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))}\nfunction processOfflineQueue(){if(offlineQueue.length===0)return;showToast('正在发送离线消息...');var msg=offlineQueue.shift();localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue));sendMessageInternal(msg.msg).then(function(){processOfflineQueue()}).catch(function(){offlineQueue.unshift(msg);localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))})}\nwindow.addEventListener('online',processOfflineQueue);\n\n// ========== 智能预加载 ==========\nfunction preloadNextChat(){\nvar currentIdx=chats.findIndex(function(c){return c.id===currentChatId});\nif(currentIdx>=0&&currentIdx<chats.length-1){\nvar nextChat=chats[currentIdx+1];\nif(!nextChat.messages||nextChat.messages.length===0){\napi('/api/conversations/'+nextChat.id+'/messages').then(function(msgs){nextChat.messages=msgs})}}}\n\n// ========== 自动保存草稿 ==========\nvar draftTimer=null;\nfunction saveDraft(){var input=$('chatInput').value;if(input&&currentChatId){localStorage.setItem('draft_'+currentChatId,input)}}\nfunction loadDraft(){if(currentChatId){var draft=localStorage.getItem('draft_'+currentChatId);if(draft)$('chatInput').value=draft}}\nfunction clearDraft(){if(currentChatId)localStorage.removeItem('draft_'+currentChatId)}\n$('chatInput').addEventListener('input',function(){clearTimeout(draftTimer);draftTimer=setTimeout(saveDraft,1000)});\n\n// ========== 消息搜索增强 ==========\nfunction searchInCurrentChat(){var q=prompt('在当前对话中搜索:');if(!q)return;var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages)return;var results=chat.messages.filter(function(m){return m.content&&m.content.toLowerCase().includes(q.toLowerCase())});if(results.length===0){alert('未找到匹配消息');return}var html='<div style=\"max-height:400px;overflow-y:auto\">';results.forEach(function(m,i){html+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:4px\">'+(m.role==='user'?'👤 用户':'🤖 助手')+'</div><div style=\"font-size:14px\">'+m.content.slice(0,200)+(m.content.length>200?'...':'')+'</div></div>'});html+='</div>';showCustomModal('搜索结果 ('+results.length+')',html,'searchResultModal')}\n\n// ========== 快速回复 ==========\nvar quickReplies=[\n{id:'continue',text:'继续',prompt:'请继续'},\n{id:'explain',text:'解释',prompt:'请详细解释一下'},\n{id:'example',text:'举例',prompt:'请举个例子'},\n{id:'simplify',text:'简化',prompt:'请用更简单的语言解释'},\n{id:'code',text:'代码',prompt:'请给出代码示例'},\n{id:'summary',text:'总结',prompt:'请总结一下要点'}\n];\nfunction showQuickReplies(){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages||chat.messages.length===0){$('quickReplies').style.display='none';return}\nvar lastMsg=chat.messages[chat.messages.length-1];\nif(lastMsg.role!=='assistant'){$('quickReplies').style.display='none';return}\nvar html=quickReplies.map(function(r){return'<button class=\"btn btn-ghost btn-sm\" onclick=\"sendQuickReply(\\''+r.prompt+'\\')\">'+r.text+'</button>'}).join('');\n$('quickReplies').innerHTML=html;\n$('quickReplies').style.display='flex'}\nfunction sendQuickReply(prompt){$('chatInput').value=prompt;sendMessage()}\n\n// ========== 数据导入导出 ==========\nfunction exportAllData(){\nif(!authToken){alert('请先登录');return}\nshowToast('正在导出数据...');\napi('/api/data/export-all',{method:'POST'}).then(function(data){\nvar blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='ai_hub_backup_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})}\n\nfunction importAllData(){\nif(!authToken){alert('请先登录');return}\nvar input=document.createElement('input');\ninput.type='file';\ninput.accept='.json';\ninput.onchange=function(e){\nvar file=e.target.files[0];\nif(!file)return;\nvar reader=new FileReader();\nreader.onload=function(ev){\ntry{\nvar data=JSON.parse(ev.target.result);\nif(!confirm('确定要导入数据?这将添加 '+\n(data.conversations?data.conversations.length:0)+' 个对话、'+\n(data.notes?data.notes.length:0)+' 个笔记'))return;\napi('/api/data/import',{method:'POST',body:JSON.stringify(data)}).then(function(result){\nshowToast('导入完成: '+result.imported.conversations+' 对话, '+result.imported.notes+' 笔记');\nloadChats()\n}).catch(function(e){alert('导入失败: '+e.message)})\n}catch(e){alert('文件格式错误')}};\nreader.readAsText(file)};\ninput.click()}\n\n// ========== 智能推荐 ==========\nfunction loadRecommendations(){\napi('/api/recommendations').then(function(data){\nif(data.features&&data.features.length>0){\nvar html='<div style=\"padding:16px;background:var(--bg3);border-radius:10px;margin-bottom:16px\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:12px\">💡 推荐功能</div><div style=\"display:flex;gap:12px;flex-wrap:wrap\">';\ndata.features.forEach(function(f){\nhtml+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;cursor:pointer;flex:1;min-width:150px\" onclick=\"showFeatureGuide(\\''+f.name+'\\')\"><span style=\"font-size:20px\">'+f.icon+'</span><div style=\"font-size:14px;font-weight:500;margin-top:8px\">'+f.name+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+f.desc+'</div></div>'});\nhtml+='</div></div>';\nvar container=$('chatMessages');\nif(container&&container.querySelector('.empty-state')){\ncontainer.innerHTML=html+container.innerHTML}}\n}).catch(function(){})}\nfunction showFeatureGuide(name){\nvar guides={\n'知识库':'点击左侧导航的\"知识库\",创建知识库并上传文档,AI 将基于您的资料回答问题。',\n'团队协作':'点击左侧导航的\"团队空间\",创建团队并邀请成员,共享对话和资源。'\n};\nalert(guides[name]||'功能介绍开发中')}\n\n// ========== 收藏消息 ==========\nfunction favoriteMessage(content){\nif(!authToken){alert('请先登录');return}\napi('/api/messages/favorite',{method:'POST',body:JSON.stringify({\nconversation_id:currentChatId,\ncontent:content\n})}).then(function(){showToast('已收藏到记忆')}).catch(function(e){alert('收藏失败: '+e.message)})}\nfunction favoriteMessageByIndex(index){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages[index])return;\nfavoriteMessage(chat.messages[index].content)}\n\n// ========== 使用分析 ==========\nfunction showUsageAnalytics(){\napi('/api/analytics/usage?days=30').then(function(data){\nvar html='<div style=\"margin-bottom:20px\"><h4 style=\"margin-bottom:12px\">📊 30天使用趋势</h4>';\nif(data.daily_usage.length>0){\nvar maxCalls=Math.max.apply(null,data.daily_usage.map(function(d){return d.calls}));\nhtml+='<div style=\"display:flex;align-items:flex-end;gap:4px;height:100px\">';\ndata.daily_usage.forEach(function(d){\nvar height=Math.max(5,(d.calls/maxCalls)*100);\nhtml+='<div style=\"flex:1;background:var(--accent);border-radius:2px 2px 0 0;height:'+height+'px\" title=\"'+d.day+': '+d.calls+'次\"></div>'});\nhtml+='</div>'}\nhtml+='</div>';\nhtml+='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">总调用次数</div><div style=\"font-size:24px;font-weight:600\">'+data.total_calls+'</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">错误率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.error_rate>5?'var(--error)':'var(--success)')+'\">'+data.error_rate+'%</div></div>';\nhtml+='</div>';\nshowCustomModal('📈 使用分析',html,'analyticsModal')\n}).catch(function(e){alert('获取分析失败: '+e.message)})}\n\n// 初始化时加载推荐\nsetTimeout(loadRecommendations,1000);\n\n// ========== 快捷键帮助 ==========\nfunction showHotkeyHelp(){\nvar html='<div style=\"display:grid;gap:8px\">';\nvar hotkeys=[\n['Ctrl + N','新建对话'],\n['Ctrl + K','全局搜索'],\n['Ctrl + D','切换主题'],\n['Ctrl + H','系统状态'],\n['Ctrl + B','批量选择'],\n['Ctrl + F','搜索当前对话'],\n['Ctrl + /','快捷键帮助'],\n['Enter','发送消息'],\n['Shift + Enter','换行'],\n['Escape','关闭弹窗']\n];\nhotkeys.forEach(function(h){\nhtml+='<div class=\"hotkey-help-item\"><span>'+h[1]+'</span><span class=\"hotkey-help-key\">'+h[0]+'</span></div>'\n});\nhtml+='</div>';\nshowCustomModal('⌨️ 快捷键帮助',html,'hotkeyHelpModal')}\n\n// ========== 欢迎引导 ==========\nfunction showWelcomeGuide(){\nif(localStorage.getItem('welcomeShown'))return;\nvar html='<div style=\"text-align:center;padding:20px\"><div style=\"font-size:48px;margin-bottom:16px\">🤖</div><h2 style=\"margin-bottom:12px\">欢迎使用 AI Hub</h2><p style=\"color:var(--text2);margin-bottom:24px\">一站式 AI 平台,支持多模型、多功能</p><div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:12px;text-align:left;margin-bottom:24px\"><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">💬</span><div style=\"font-weight:500;margin-top:8px\">多模型对话</div><div style=\"font-size:12px;color:var(--text2)\">支持 OpenAI、Claude、Gemini 等</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">🎨</span><div style=\"font-weight:500;margin-top:8px\">图片生成</div><div style=\"font-size:12px;color:var(--text2)\">DALL-E 3 AI 绘图</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">📚</span><div style=\"font-weight:500;margin-top:8px\">知识库</div><div style=\"font-size:12px;color:var(--text2)\">上传文档,智能问答</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">👥</span><div style=\"font-weight:500;margin-top:8px\">团队协作</div><div style=\"font-size:12px;color:var(--text2)\">多人共享对话和资源</div></div></div><button class=\"btn btn-primary\" onclick=\"closeModal(\\'welcomeModal\\');localStorage.setItem(\\'welcomeShown\\',\\'1\\')\">开始使用</button></div>';\nshowCustomModal('',html,'welcomeModal')}\nsetTimeout(showWelcomeGuide,500);\n\nconsole.log('🤖 AI Hub v2.0.0 - Enhanced');\n</script>\n</body>\n</html>\n"}, "aaff7e99657fb8041f8505696621cc289e4b50b4": {"t": 1785765467.5360947, "n": 209714, "h": "a9df603b8b7ab195", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"theme-color\" content=\"#0f0f1a\">\n<meta name=\"description\" content=\"AI Hub - 统一 AI 平台\">\n<link rel=\"manifest\" href=\"/static/manifest.json\">\n<link rel=\"apple-touch-icon\" href=\"/static/icon-192.png\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"workflows\"><span class=\"nav-item-icon\">🤖</span> Agent 工作流</div>\n<div class=\"nav-item\" data-page=\"code-runner\"><span class=\"nav-item-icon\">▶️</span> 代码运行</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" onclick=\"showHealthDashboard()\"><span class=\"nav-item-icon\">🖥️</span> 系统状态</div>\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\" title=\"批量操作\">☑️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div id=\"batchActions\" style=\"display:none;padding:8px;background:var(--bg3);gap:8px;align-items:center\">\n<span style=\"font-size:12px\">已选 <span id=\"selectedCount\">0</span> 个</span>\n<button class=\"btn btn-danger btn-sm\" onclick=\"batchDeleteChats()\">删除</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"batchExportChats()\">导出</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\">取消</button>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"quickReplies\" style=\"display:none;padding:8px 0;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap\"></div>\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateImage()\" title=\"生成图片\">🎨</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateMindmap()\" title=\"生成思维导图\">🧠</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"saveAsTemplate()\" title=\"保存为模板\">💾</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">双因素认证 (2FA)<br><small style=\"color:var(--text2)\">使用 Google Authenticator 等应用增强账户安全</small></div><div style=\"display:flex;gap:8px\"><span id=\"2faStatus\" style=\"color:var(--text2)\">未启用</span><button class=\"btn btn-ghost btn-sm\" onclick=\"setup2FA()\" id=\"2faBtn\">设置</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录设备管理</div><button class=\"btn btn-ghost btn-sm\" onclick=\"alert('功能开发中')\">查看设备</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">修改密码</div><button class=\"btn btn-ghost btn-sm\" onclick=\"showChangePasswordModal()\">修改</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复<br><small style=\"color:var(--text2)\">导出/导入所有数据(对话、笔记、记忆、设置)</small></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-primary\" onclick=\"exportAllData()\">📤 导出全部</button><button class=\"btn btn-ghost\" onclick=\"importAllData()\">📥 导入数据</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据库优化<br><small style=\"color:var(--text2)\">清理过期数据,优化数据库性能</small></div><button class=\"btn btn-ghost\" onclick=\"optimizeDatabase()\">🔧 优化数据库</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n<button class=\"btn btn-primary\" onclick=\"showUsageAnalytics()\">📈 详细分析</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Agent 工作流页 -->\n<div id=\"page-workflows\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🤖</span> Agent 工作流</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建多步骤自动化任务,让 AI 按流程完成复杂工作</p>\n<div id=\"workflowTemplates\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px\"></div>\n</div>\n<div class=\"settings-section\" id=\"workflowRunner\" style=\"display:none\">\n<h4><span>▶️</span> 运行工作流</h4>\n<div id=\"workflowInputs\"></div>\n<button class=\"btn btn-primary\" onclick=\"executeWorkflow()\">🚀 执行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('workflowRunner').style.display='none'\">取消</button>\n</div>\n<div class=\"settings-section\" id=\"workflowResults\" style=\"display:none\">\n<h4><span>📋</span> 执行结果</h4>\n<div id=\"workflowResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 代码运行器页 -->\n<div id=\"page-code-runner\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>▶️</span> 代码运行器</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">在线运行 Python / JavaScript 代码</p>\n<div class=\"form-group\">\n<label>语言</label>\n<select id=\"codeLanguage\" style=\"width:150px\">\n<option value=\"python\">Python</option>\n<option value=\"javascript\">JavaScript</option>\n</select>\n</div>\n<div class=\"form-group\">\n<label>代码</label>\n<textarea id=\"codeInput\" rows=\"12\" style=\"font-family:monospace;font-size:13px\" placeholder=\"# 输入代码...\nprint('Hello, World!')\"></textarea>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-primary\" onclick=\"runCode()\">▶️ 运行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('codeInput').value=''\">清空</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 输出结果</h4>\n<pre id=\"codeOutput\" style=\"background:var(--bg);padding:16px;border-radius:8px;min-height:100px;font-family:monospace;font-size:13px;white-space:pre-wrap\">等待运行...</pre>\n</div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>系统状态</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + H</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量选择模式</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + B</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>批量导出</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>搜索当前对话</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + F</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换主题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + D</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><div class=\"form-group\" id=\"auth2FAGroup\" style=\"display:none\"><label>2FA 验证码</label><input type=\"text\" id=\"auth2FACode\" placeholder=\"6位验证码\" maxlength=\"6\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><div style=\"display:flex;align-items:center;margin:16px 0\"><div style=\"flex:1;height:1px;background:var(--border)\"></div><span style=\"padding:0 12px;color:var(--text2);font-size:12px\">或</span><div style=\"flex:1;height:1px;background:var(--border)\"></div></div><button class=\"btn btn-ghost\" style=\"width:100%;display:flex;align-items:center;justify-content:center;gap:8px\" onclick=\"loginWithGithub()\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg> 使用 GitHub 登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();if(n.dataset.page==='workflows')loadWorkflowTemplates();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{\n// 先显示置顶的对话\nvar pinnedChats=chats.filter(function(c){return c.pinned});\nvar normalChats=chats.filter(function(c){return !c.pinned&&!c.archived});\nif(pinnedChats.length>0){html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2)\">📌 置顶</div>';pinnedChats.forEach(function(c){html+=renderChatItem(c)})}\nif(normalChats.length>0){if(pinnedChats.length>0)html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2);margin-top:8px\">💬 对话</div>';normalChats.forEach(function(c){html+=renderChatItem(c)})}}$('chatList').innerHTML=html}\nfunction renderChatItem(c){var selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';var checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';var pinIcon=c.pinned?'📌':'💬';return'<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" style=\"'+selected+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">'+pinIcon+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var chat=chats.find(function(c){return c.id===id});var pinText=chat&&chat.pinned?'📌 取消置顶':'📌 置顶';var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"togglePinChat(\\''+id+'\\')\">'+pinText+'</div><div onclick=\"archiveChat(\\''+id+'\\')\">📦 归档</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction togglePinChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.pinned=!chat.pinned;saveChats();renderChats();showToast(chat.pinned?'已置顶':'已取消置顶');if(authToken){api('/api/conversations/'+id+'/pin',{method:'POST'}).catch(function(){})}}\nfunction archiveChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.archived=true;chats=chats.filter(function(c){return c.id!==id});saveChats();renderChats();showToast('已归档');if(authToken){api('/api/conversations/'+id+'/archive',{method:'POST'}).catch(function(){})}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Agent 工作流\nvar workflowTemplates=[];\nvar currentWorkflow=null;\nfunction loadWorkflowTemplates(){api('/api/workflows/templates').then(function(data){workflowTemplates=data;renderWorkflowTemplates()}).catch(function(e){console.error('加载工作流失败:',e)})}\nfunction renderWorkflowTemplates(){var html=workflowTemplates.map(function(w){return'<div style=\"background:var(--bg);border-radius:12px;padding:20px;cursor:pointer\" onclick=\"selectWorkflow(\\''+w.id+'\\')\"><div style=\"display:flex;align-items:center;gap:12px;margin-bottom:12px\"><span style=\"font-size:24px\">🤖</span><div><strong>'+w.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+w.steps.length+' 个步骤</div></div></div><p style=\"font-size:13px;color:var(--text2);line-height:1.5\">'+w.description+'</p></div>'}).join('');$('workflowTemplates').innerHTML=html||'<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无工作流模板</div>'}\nfunction selectWorkflow(id){currentWorkflow=workflowTemplates.find(function(w){return w.id===id});if(!currentWorkflow)return;var inputs=[];currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')&&inputs.indexOf(key)===-1)inputs.push(key)})}});var html=inputs.map(function(key){return'<div class=\"form-group\"><label>'+key+'</label><textarea id=\"wf_'+key+'\" rows=\"3\" placeholder=\"输入 '+key+'\"></textarea></div>'}).join('');$('workflowInputs').innerHTML='<h5 style=\"margin-bottom:16px\">'+currentWorkflow.name+'</h5>'+html;$('workflowRunner').style.display='block';$('workflowResults').style.display='none'}\nfunction executeWorkflow(){if(!currentWorkflow){alert('请先选择工作流');return}var inputData={};currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')){var el=$('wf_'+key);if(el)inputData[key]=el.value}})}});$('workflowResultsContent').innerHTML='<div style=\"text-align:center;padding:40px\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px;color:var(--text2)\">正在执行工作流...</p></div>';$('workflowResults').style.display='block';api('/api/workflows/run',{method:'POST',body:JSON.stringify({name:currentWorkflow.name,steps:currentWorkflow.steps,input_data:inputData})}).then(function(data){var html='';for(var key in data.results){html+='<div style=\"background:var(--bg);border-radius:10px;padding:16px;margin-bottom:12px\"><div style=\"font-weight:600;margin-bottom:8px;color:var(--accent)\">'+key+'</div><div style=\"font-size:14px;line-height:1.6;white-space:pre-wrap\">'+data.results[key]+'</div></div>'}$('workflowResultsContent').innerHTML=html}).catch(function(e){$('workflowResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">执行失败: '+e.message+'</div>'})}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// GitHub 登录\nfunction loginWithGithub(){window.location.href='/api/auth/github'}\n// 2FA 设置\nfunction setup2FA(){if(!authToken){alert('请先登录');return}api('/api/auth/2fa/setup',{method:'POST'}).then(function(data){var html='<div style=\"text-align:center\"><img src=\"'+data.qr_code+'\" style=\"width:200px;height:200px;border-radius:8px\"><p style=\"margin:16px 0;color:var(--text2);font-size:13px\">使用 Google Authenticator 扫描二维码</p><div class=\"form-group\"><label>输入6位验证码确认</label><input type=\"text\" id=\"verify2FACode\" placeholder=\"000000\" maxlength=\"6\" style=\"text-align:center;font-size:20px;letter-spacing:8px\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"verify2FA()\">确认启用</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'2faModal\\')\">取消</button></div></div>';showCustomModal('设置双因素认证',html,'2faModal')}).catch(function(e){alert('设置失败: '+e.message)})}\nfunction verify2FA(){var code=$('verify2FACode').value.trim();if(code.length!==6){alert('请输入6位验证码');return}api('/api/auth/2fa/verify',{method:'POST',body:JSON.stringify({code:code})}).then(function(data){closeModal('2faModal');$('2faStatus').textContent='已启用';$('2faStatus').style.color='var(--success)';$('2faBtn').textContent='禁用';$('2faBtn').onclick=disable2FA;showToast('2FA 已启用')}).catch(function(e){alert('验证失败: '+e.message)})}\nfunction disable2FA(){var code=prompt('输入6位验证码以禁用 2FA:');if(!code)return;api('/api/auth/2fa/disable',{method:'POST',body:JSON.stringify({code:code})}).then(function(){$('2faStatus').textContent='未启用';$('2faStatus').style.color='var(--text2)';$('2faBtn').textContent='设置';$('2faBtn').onclick=setup2FA;showToast('2FA 已禁用')}).catch(function(e){alert('禁用失败: '+e.message)})}\nfunction showChangePasswordModal(){var html='<div class=\"form-group\"><label>当前密码</label><input type=\"password\" id=\"oldPassword\"></div><div class=\"form-group\"><label>新密码</label><input type=\"password\" id=\"newPassword\"></div><div class=\"form-group\"><label>确认新密码</label><input type=\"password\" id=\"confirmPassword\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"changePassword()\">修改</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pwdModal\\')\">取消</button></div>';showCustomModal('修改密码',html,'pwdModal')}\nfunction changePassword(){var oldPwd=$('oldPassword').value,newPwd=$('newPassword').value,confirmPwd=$('confirmPassword').value;if(!oldPwd||!newPwd){alert('请填写密码');return}if(newPwd!==confirmPwd){alert('两次密码不一致');return}alert('密码修改功能开发中')}\n// 检查 URL 中的 token(OAuth 回调)\n(function(){var params=new URLSearchParams(window.location.search);var token=params.get('token');if(token){localStorage.setItem('token',token);authToken=token;window.history.replaceState({},document.title,'/');checkAuth()}})();\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\n// 代码运行器\nfunction runCode(){var code=$('codeInput').value;var lang=$('codeLanguage').value;if(!code.trim()){alert('请输入代码');return}$('codeOutput').textContent='运行中...';$('codeOutput').style.color='var(--text2)';api('/api/code/run',{method:'POST',body:JSON.stringify({code:code,language:lang,timeout:5})}).then(function(data){if(data.success){$('codeOutput').textContent=data.output||'(无输出)';$('codeOutput').style.color='var(--success)'}else{$('codeOutput').textContent='错误: '+(data.error||'未知错误')+'\\n'+data.output;$('codeOutput').style.color='var(--error)'}}).catch(function(e){$('codeOutput').textContent='请求失败: '+e.message;$('codeOutput').style.color='var(--error)'})}\n// 思维导图\nfunction generateMindmap(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}showToast('正在生成思维导图...');api('/api/mindmap/generate',{method:'POST',body:JSON.stringify({messages:chat.messages,title:chat.title})}).then(function(data){renderMindmap(data.nodes)}).catch(function(e){alert('生成失败: '+e.message)})}\nfunction renderMindmap(nodes){var html='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.8);z-index:2000;display:flex;align-items:center;justify-content:center\" onclick=\"if(event.target===this)this.remove()\"><div style=\"background:var(--bg2);border-radius:16px;padding:24px;max-width:800px;max-height:80vh;overflow:auto\"><h3 style=\"margin-bottom:16px\">🧠 思维导图</h3><div id=\"mindmapContent\" style=\"padding:20px\"></div><button class=\"btn btn-ghost\" onclick=\"this.parentElement.parentElement.remove()\">关闭</button></div></div>';document.body.insertAdjacentHTML('beforeend',html);var content='';function renderNode(node,level){var indent=level*24;content+='<div style=\"margin-left:'+indent+'px;padding:8px 12px;margin-bottom:4px;background:var(--bg'+(level>0?'3':'')+');border-radius:6px;border-left:3px solid var(--accent)\">'+(level>0?'├─ ':'')+node.label+'</div>';if(node.children){node.children.forEach(function(c){renderNode(c,level+1)})}}if(nodes&&nodes.length)renderNode(nodes[0],0);$('mindmapContent').innerHTML=content||'<p style=\"color:var(--text2)\">无法生成思维导图</p>'}\n// 保存对话为模板\nfunction saveAsTemplate(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}var name=prompt('模板名称:',chat.title);if(!name)return;api('/api/chat-templates',{method:'POST',body:JSON.stringify({name:name,messages:chat.messages})}).then(function(){showToast('已保存为模板')}).catch(function(e){alert('保存失败: '+e.message)})}\n// 用量配额\nfunction loadQuota(){api('/api/quota').then(function(data){var html='<div style=\"margin-bottom:16px\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Token 使用量</span><span>'+formatNumber(data.tokens_used)+' / '+formatNumber(data.tokens_limit)+'</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;overflow:hidden\"><div style=\"background:var(--accent);height:100%;width:'+data.usage_percent+'%\"></div></div></div><p style=\"font-size:12px;color:var(--text2)\">当前套餐: '+data.plan+'</p>';if($('quotaInfo'))$('quotaInfo').innerHTML=html}).catch(function(e){console.error(e)})}\n// PWA 注册\nif('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js').then(function(reg){console.log('SW registered');if('Notification' in window&&Notification.permission==='default'){Notification.requestPermission()}}).catch(function(e){console.error('SW failed:',e)})}\n// 图片生成\nfunction generateImage(){var prompt=prompt('输入图片描述:');if(!prompt)return;showToast('正在生成图片...');api('/api/images/generate',{method:'POST',body:JSON.stringify({prompt:prompt})}).then(function(data){var img='<img src=\"'+data.url+'\" style=\"max-width:100%;border-radius:8px\">';var chat=chats.find(function(c){return c.id===currentChatId});if(chat){chat.messages.push({role:'assistant',content:'![生成的图片]('+data.url+')\\n\\n'+data.revised_prompt});saveChats();renderMessages()}showToast('图片已生成')}).catch(function(e){alert('生成失败: '+e.message)})}\n// TTS 语音合成\nfunction speakText(text){api('/api/audio/tts',{method:'POST',body:JSON.stringify({text:text,voice:'alloy'})}).then(function(data){var audio=new Audio(data.audio);audio.play();showToast('正在播放')}).catch(function(e){if('speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(text);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('TTS 失败: '+e.message)}})}\n// 内容过滤\nfunction filterContent(text){return api('/api/content/filter',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data})}\n// 数据脱敏\nfunction maskData(text){return api('/api/data/mask',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data.masked})}\n// 备份\nfunction createBackup(){api('/api/backup',{method:'POST'}).then(function(data){showToast('备份已创建: '+data.path)}).catch(function(e){alert('备份失败: '+e.message)})}\n// 离线检测\nwindow.addEventListener('online',function(){showToast('网络已恢复')});\nwindow.addEventListener('offline',function(){showToast('网络已断开,部分功能不可用')});\n\n// ========== 性能监控面板 ==========\nfunction showHealthDashboard(){\napi('/api/health/detailed').then(function(data){\nvar html='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">CPU 使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.cpu_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.cpu_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">内存使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.memory_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.memory_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">磁盘使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.disk_percent>90?'var(--error)':'var(--success)')+'\">'+data.system.disk_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">数据库延迟</div><div style=\"font-size:24px;font-weight:600;color:'+(data.components.database.latency_ms>100?'var(--warning)':'var(--success)')+'\">'+data.components.database.latency_ms+'ms</div></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:10px\">';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>缓存</span><span>'+data.components.cache.size+'/'+data.components.cache.max_size+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Redis</span><span style=\"color:'+(data.components.redis.status==='healthy'?'var(--success)':'var(--warning)')+'\">'+data.components.redis.status+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between\"><span>待处理任务</span><span>'+data.components.task_queue.pending_tasks+'</span></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;text-align:center;font-size:12px;color:var(--text2)\">版本 '+data.version+' · 运行时间 '+formatUptime(data.uptime_seconds)+'</div>';\nshowCustomModal('🖥️ 系统状态',html,'healthModal')\n}).catch(function(e){alert('获取状态失败: '+e.message)})}\nfunction formatUptime(seconds){var h=Math.floor(seconds/3600);var m=Math.floor((seconds%3600)/60);return h+'小时'+m+'分钟'}\n\n// ========== 批量操作 ==========\nvar batchMode=false;\nvar selectedChats=[];\nfunction toggleBatchMode(){batchMode=!batchMode;selectedChats=[];if(batchMode){$('batchActions').style.display='flex';showToast('已进入批量选择模式')}else{$('batchActions').style.display='none'}renderChatList()}\nfunction toggleChatSelection(id,e){if(!batchMode)return;e.stopPropagation();var idx=selectedChats.indexOf(id);if(idx>=0){selectedChats.splice(idx,1)}else{selectedChats.push(id)}renderChatList();$('selectedCount').textContent=selectedChats.length}\nfunction batchDeleteChats(){if(selectedChats.length===0){alert('请先选择对话');return}if(!confirm('确定删除 '+selectedChats.length+' 个对话?'))return;api('/api/conversations/batch-delete',{method:'POST',body:JSON.stringify({ids:selectedChats})}).then(function(data){showToast('已删除 '+data.deleted+' 个对话');selectedChats=[];batchMode=false;$('batchActions').style.display='none';loadChats()}).catch(function(e){alert('删除失败: '+e.message)})}\nfunction batchExportChats(){if(selectedChats.length===0){alert('请先选择对话');return}api('/api/messages/batch-export',{method:'POST',body:JSON.stringify({conversation_ids:selectedChats,format:'json'})}).then(function(data){var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='conversations_export.json';a.click();showToast('已导出 '+data.count+' 个对话')}).catch(function(e){alert('导出失败: '+e.message)})}\n\n// ========== 数据库优化 ==========\nfunction optimizeDatabase(){if(!confirm('确定要优化数据库?这将清理过期数据。'))return;showToast('正在优化...');api('/api/admin/optimize-db',{method:'POST'}).then(function(data){showToast(data.message)}).catch(function(e){alert('优化失败: '+e.message)})}\n\n// ========== 快捷键增强 ==========\ndocument.addEventListener('keydown',function(e){\nif(e.ctrlKey&&e.key==='h'){e.preventDefault();showHealthDashboard()}\nif(e.ctrlKey&&e.key==='b'){e.preventDefault();toggleBatchMode()}\nif(e.ctrlKey&&e.shiftKey&&e.key==='E'){e.preventDefault();batchExportChats()}\nif(e.ctrlKey&&e.key==='f'){e.preventDefault();searchInCurrentChat()}\nif(e.ctrlKey&&e.key==='/'||e.key==='?'){e.preventDefault();showHotkeyHelp()}\n});\n\n// ========== 性能优化:虚拟滚动 ==========\nfunction renderChatListVirtual(){\nvar container=$('chatList');\nvar itemHeight=60;\nvar visibleCount=Math.ceil(container.clientHeight/itemHeight)+2;\nvar scrollTop=container.scrollTop;\nvar startIndex=Math.floor(scrollTop/itemHeight);\nvar endIndex=Math.min(startIndex+visibleCount,chats.length);\nvar html='<div style=\"height:'+(startIndex*itemHeight)+'px\"></div>';\nfor(var i=startIndex;i<endIndex;i++){\nvar c=chats[i];\nvar active=c.id===currentChatId?'active':'';\nvar selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';\nvar checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';\nhtml+='<div class=\"sidebar-item '+active+'\" style=\"'+selected+'\" onclick=\"loadChat(\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+c.title+'</div><div class=\"sidebar-item-desc\">'+(c.messages.length||0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" style=\"opacity:0\" onclick=\"deleteChat(\\''+c.id+'\\',event)\">🗑️</button></div>'\n}\nhtml+='<div style=\"height:'+((chats.length-endIndex)*itemHeight)+'px\"></div>';\ncontainer.innerHTML=html}\n\n// ========== 请求重试机制 ==========\nasync function apiWithRetry(url,options,maxRetries=3){\nfor(var i=0;i<maxRetries;i++){\ntry{return await api(url,options)}\ncatch(e){\nif(i===maxRetries-1)throw e;\nawait new Promise(function(r){setTimeout(r,1000*(i+1))});\nconsole.log('Retrying request...',i+1)\n}}}\n\n// ========== 消息队列(离线支持) ==========\nvar offlineQueue=JSON.parse(localStorage.getItem('offlineQueue')||'[]');\nfunction queueOfflineMessage(msg){offlineQueue.push({msg:msg,time:Date.now()});localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))}\nfunction processOfflineQueue(){if(offlineQueue.length===0)return;showToast('正在发送离线消息...');var msg=offlineQueue.shift();localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue));sendMessageInternal(msg.msg).then(function(){processOfflineQueue()}).catch(function(){offlineQueue.unshift(msg);localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))})}\nwindow.addEventListener('online',processOfflineQueue);\n\n// ========== 智能预加载 ==========\nfunction preloadNextChat(){\nvar currentIdx=chats.findIndex(function(c){return c.id===currentChatId});\nif(currentIdx>=0&&currentIdx<chats.length-1){\nvar nextChat=chats[currentIdx+1];\nif(!nextChat.messages||nextChat.messages.length===0){\napi('/api/conversations/'+nextChat.id+'/messages').then(function(msgs){nextChat.messages=msgs})}}}\n\n// ========== 自动保存草稿 ==========\nvar draftTimer=null;\nfunction saveDraft(){var input=$('chatInput').value;if(input&&currentChatId){localStorage.setItem('draft_'+currentChatId,input)}}\nfunction loadDraft(){if(currentChatId){var draft=localStorage.getItem('draft_'+currentChatId);if(draft)$('chatInput').value=draft}}\nfunction clearDraft(){if(currentChatId)localStorage.removeItem('draft_'+currentChatId)}\n$('chatInput').addEventListener('input',function(){clearTimeout(draftTimer);draftTimer=setTimeout(saveDraft,1000)});\n\n// ========== 消息搜索增强 ==========\nfunction searchInCurrentChat(){var q=prompt('在当前对话中搜索:');if(!q)return;var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages)return;var results=chat.messages.filter(function(m){return m.content&&m.content.toLowerCase().includes(q.toLowerCase())});if(results.length===0){alert('未找到匹配消息');return}var html='<div style=\"max-height:400px;overflow-y:auto\">';results.forEach(function(m,i){html+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:4px\">'+(m.role==='user'?'👤 用户':'🤖 助手')+'</div><div style=\"font-size:14px\">'+m.content.slice(0,200)+(m.content.length>200?'...':'')+'</div></div>'});html+='</div>';showCustomModal('搜索结果 ('+results.length+')',html,'searchResultModal')}\n\n// ========== 快速回复 ==========\nvar quickReplies=[\n{id:'continue',text:'继续',prompt:'请继续'},\n{id:'explain',text:'解释',prompt:'请详细解释一下'},\n{id:'example',text:'举例',prompt:'请举个例子'},\n{id:'simplify',text:'简化',prompt:'请用更简单的语言解释'},\n{id:'code',text:'代码',prompt:'请给出代码示例'},\n{id:'summary',text:'总结',prompt:'请总结一下要点'}\n];\nfunction showQuickReplies(){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages||chat.messages.length===0){$('quickReplies').style.display='none';return}\nvar lastMsg=chat.messages[chat.messages.length-1];\nif(lastMsg.role!=='assistant'){$('quickReplies').style.display='none';return}\nvar html=quickReplies.map(function(r){return'<button class=\"btn btn-ghost btn-sm\" onclick=\"sendQuickReply(\\''+r.prompt+'\\')\">'+r.text+'</button>'}).join('');\n$('quickReplies').innerHTML=html;\n$('quickReplies').style.display='flex'}\nfunction sendQuickReply(prompt){$('chatInput').value=prompt;sendMessage()}\n\n// ========== 数据导入导出 ==========\nfunction exportAllData(){\nif(!authToken){alert('请先登录');return}\nshowToast('正在导出数据...');\napi('/api/data/export-all',{method:'POST'}).then(function(data){\nvar blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='ai_hub_backup_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})}\n\nfunction importAllData(){\nif(!authToken){alert('请先登录');return}\nvar input=document.createElement('input');\ninput.type='file';\ninput.accept='.json';\ninput.onchange=function(e){\nvar file=e.target.files[0];\nif(!file)return;\nvar reader=new FileReader();\nreader.onload=function(ev){\ntry{\nvar data=JSON.parse(ev.target.result);\nif(!confirm('确定要导入数据?这将添加 '+\n(data.conversations?data.conversations.length:0)+' 个对话、'+\n(data.notes?data.notes.length:0)+' 个笔记'))return;\napi('/api/data/import',{method:'POST',body:JSON.stringify(data)}).then(function(result){\nshowToast('导入完成: '+result.imported.conversations+' 对话, '+result.imported.notes+' 笔记');\nloadChats()\n}).catch(function(e){alert('导入失败: '+e.message)})\n}catch(e){alert('文件格式错误')}};\nreader.readAsText(file)};\ninput.click()}\n\n// ========== 智能推荐 ==========\nfunction loadRecommendations(){\napi('/api/recommendations').then(function(data){\nif(data.features&&data.features.length>0){\nvar html='<div style=\"padding:16px;background:var(--bg3);border-radius:10px;margin-bottom:16px\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:12px\">💡 推荐功能</div><div style=\"display:flex;gap:12px;flex-wrap:wrap\">';\ndata.features.forEach(function(f){\nhtml+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;cursor:pointer;flex:1;min-width:150px\" onclick=\"showFeatureGuide(\\''+f.name+'\\')\"><span style=\"font-size:20px\">'+f.icon+'</span><div style=\"font-size:14px;font-weight:500;margin-top:8px\">'+f.name+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+f.desc+'</div></div>'});\nhtml+='</div></div>';\nvar container=$('chatMessages');\nif(container&&container.querySelector('.empty-state')){\ncontainer.innerHTML=html+container.innerHTML}}\n}).catch(function(){})}\nfunction showFeatureGuide(name){\nvar guides={\n'知识库':'点击左侧导航的\"知识库\",创建知识库并上传文档,AI 将基于您的资料回答问题。',\n'团队协作':'点击左侧导航的\"团队空间\",创建团队并邀请成员,共享对话和资源。'\n};\nalert(guides[name]||'功能介绍开发中')}\n\n// ========== 收藏消息 ==========\nfunction favoriteMessage(content){\nif(!authToken){alert('请先登录');return}\napi('/api/messages/favorite',{method:'POST',body:JSON.stringify({\nconversation_id:currentChatId,\ncontent:content\n})}).then(function(){showToast('已收藏到记忆')}).catch(function(e){alert('收藏失败: '+e.message)})}\n\n// ========== 使用分析 ==========\nfunction showUsageAnalytics(){\napi('/api/analytics/usage?days=30').then(function(data){\nvar html='<div style=\"margin-bottom:20px\"><h4 style=\"margin-bottom:12px\">📊 30天使用趋势</h4>';\nif(data.daily_usage.length>0){\nvar maxCalls=Math.max.apply(null,data.daily_usage.map(function(d){return d.calls}));\nhtml+='<div style=\"display:flex;align-items:flex-end;gap:4px;height:100px\">';\ndata.daily_usage.forEach(function(d){\nvar height=Math.max(5,(d.calls/maxCalls)*100);\nhtml+='<div style=\"flex:1;background:var(--accent);border-radius:2px 2px 0 0;height:'+height+'px\" title=\"'+d.day+': '+d.calls+'次\"></div>'});\nhtml+='</div>'}\nhtml+='</div>';\nhtml+='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">总调用次数</div><div style=\"font-size:24px;font-weight:600\">'+data.total_calls+'</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">错误率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.error_rate>5?'var(--error)':'var(--success)')+'\">'+data.error_rate+'%</div></div>';\nhtml+='</div>';\nshowCustomModal('📈 使用分析',html,'analyticsModal')\n}).catch(function(e){alert('获取分析失败: '+e.message)})}\n\n// 初始化时加载推荐\nsetTimeout(loadRecommendations,1000);\n\n// ========== 快捷键帮助 ==========\nfunction showHotkeyHelp(){\nvar html='<div style=\"display:grid;gap:8px\">';\nvar hotkeys=[\n['Ctrl + N','新建对话'],\n['Ctrl + K','全局搜索'],\n['Ctrl + D','切换主题'],\n['Ctrl + H','系统状态'],\n['Ctrl + B','批量选择'],\n['Ctrl + F','搜索当前对话'],\n['Ctrl + /','快捷键帮助'],\n['Enter','发送消息'],\n['Shift + Enter','换行'],\n['Escape','关闭弹窗']\n];\nhotkeys.forEach(function(h){\nhtml+='<div class=\"hotkey-help-item\"><span>'+h[1]+'</span><span class=\"hotkey-help-key\">'+h[0]+'</span></div>'\n});\nhtml+='</div>';\nshowCustomModal('⌨️ 快捷键帮助',html,'hotkeyHelpModal')}\n\n// ========== 欢迎引导 ==========\nfunction showWelcomeGuide(){\nif(localStorage.getItem('welcomeShown'))return;\nvar html='<div style=\"text-align:center;padding:20px\"><div style=\"font-size:48px;margin-bottom:16px\">🤖</div><h2 style=\"margin-bottom:12px\">欢迎使用 AI Hub</h2><p style=\"color:var(--text2);margin-bottom:24px\">一站式 AI 平台,支持多模型、多功能</p><div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:12px;text-align:left;margin-bottom:24px\"><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">💬</span><div style=\"font-weight:500;margin-top:8px\">多模型对话</div><div style=\"font-size:12px;color:var(--text2)\">支持 OpenAI、Claude、Gemini 等</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">🎨</span><div style=\"font-weight:500;margin-top:8px\">图片生成</div><div style=\"font-size:12px;color:var(--text2)\">DALL-E 3 AI 绘图</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">📚</span><div style=\"font-weight:500;margin-top:8px\">知识库</div><div style=\"font-size:12px;color:var(--text2)\">上传文档,智能问答</div></div><div style=\"padding:16px;background:var(--bg);border-radius:10px\"><span style=\"font-size:20px\">👥</span><div style=\"font-weight:500;margin-top:8px\">团队协作</div><div style=\"font-size:12px;color:var(--text2)\">多人共享对话和资源</div></div></div><button class=\"btn btn-primary\" onclick=\"closeModal(\\'welcomeModal\\');localStorage.setItem(\\'welcomeShown\\',\\'1\\')\">开始使用</button></div>';\nshowCustomModal('',html,'welcomeModal')}\nsetTimeout(showWelcomeGuide,500);\n\nconsole.log('🤖 AI Hub v2.0.0 - Enhanced');\n</script>\n</body>\n</html>\n"}, "5dc8924c8e61e5d99a0102920ce2b9cfce5b00b6": {"t": 1785765469.326672, "n": 206005, "h": "a78f350f35d2c8dc", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"theme-color\" content=\"#0f0f1a\">\n<meta name=\"description\" content=\"AI Hub - 统一 AI 平台\">\n<link rel=\"manifest\" href=\"/static/manifest.json\">\n<link rel=\"apple-touch-icon\" href=\"/static/icon-192.png\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"workflows\"><span class=\"nav-item-icon\">🤖</span> Agent 工作流</div>\n<div class=\"nav-item\" data-page=\"code-runner\"><span class=\"nav-item-icon\">▶️</span> 代码运行</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" onclick=\"showHealthDashboard()\"><span class=\"nav-item-icon\">🖥️</span> 系统状态</div>\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\" title=\"批量操作\">☑️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div id=\"batchActions\" style=\"display:none;padding:8px;background:var(--bg3);gap:8px;align-items:center\">\n<span style=\"font-size:12px\">已选 <span id=\"selectedCount\">0</span> 个</span>\n<button class=\"btn btn-danger btn-sm\" onclick=\"batchDeleteChats()\">删除</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"batchExportChats()\">导出</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\">取消</button>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"quickReplies\" style=\"display:none;padding:8px 0;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap\"></div>\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateImage()\" title=\"生成图片\">🎨</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateMindmap()\" title=\"生成思维导图\">🧠</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"saveAsTemplate()\" title=\"保存为模板\">💾</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">双因素认证 (2FA)<br><small style=\"color:var(--text2)\">使用 Google Authenticator 等应用增强账户安全</small></div><div style=\"display:flex;gap:8px\"><span id=\"2faStatus\" style=\"color:var(--text2)\">未启用</span><button class=\"btn btn-ghost btn-sm\" onclick=\"setup2FA()\" id=\"2faBtn\">设置</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录设备管理</div><button class=\"btn btn-ghost btn-sm\" onclick=\"alert('功能开发中')\">查看设备</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">修改密码</div><button class=\"btn btn-ghost btn-sm\" onclick=\"showChangePasswordModal()\">修改</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复<br><small style=\"color:var(--text2)\">导出/导入所有数据(对话、笔记、记忆、设置)</small></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-primary\" onclick=\"exportAllData()\">📤 导出全部</button><button class=\"btn btn-ghost\" onclick=\"importAllData()\">📥 导入数据</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据库优化<br><small style=\"color:var(--text2)\">清理过期数据,优化数据库性能</small></div><button class=\"btn btn-ghost\" onclick=\"optimizeDatabase()\">🔧 优化数据库</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n<button class=\"btn btn-primary\" onclick=\"showUsageAnalytics()\">📈 详细分析</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Agent 工作流页 -->\n<div id=\"page-workflows\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🤖</span> Agent 工作流</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建多步骤自动化任务,让 AI 按流程完成复杂工作</p>\n<div id=\"workflowTemplates\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px\"></div>\n</div>\n<div class=\"settings-section\" id=\"workflowRunner\" style=\"display:none\">\n<h4><span>▶️</span> 运行工作流</h4>\n<div id=\"workflowInputs\"></div>\n<button class=\"btn btn-primary\" onclick=\"executeWorkflow()\">🚀 执行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('workflowRunner').style.display='none'\">取消</button>\n</div>\n<div class=\"settings-section\" id=\"workflowResults\" style=\"display:none\">\n<h4><span>📋</span> 执行结果</h4>\n<div id=\"workflowResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 代码运行器页 -->\n<div id=\"page-code-runner\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>▶️</span> 代码运行器</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">在线运行 Python / JavaScript 代码</p>\n<div class=\"form-group\">\n<label>语言</label>\n<select id=\"codeLanguage\" style=\"width:150px\">\n<option value=\"python\">Python</option>\n<option value=\"javascript\">JavaScript</option>\n</select>\n</div>\n<div class=\"form-group\">\n<label>代码</label>\n<textarea id=\"codeInput\" rows=\"12\" style=\"font-family:monospace;font-size:13px\" placeholder=\"# 输入代码...\nprint('Hello, World!')\"></textarea>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-primary\" onclick=\"runCode()\">▶️ 运行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('codeInput').value=''\">清空</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 输出结果</h4>\n<pre id=\"codeOutput\" style=\"background:var(--bg);padding:16px;border-radius:8px;min-height:100px;font-family:monospace;font-size:13px;white-space:pre-wrap\">等待运行...</pre>\n</div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><div class=\"form-group\" id=\"auth2FAGroup\" style=\"display:none\"><label>2FA 验证码</label><input type=\"text\" id=\"auth2FACode\" placeholder=\"6位验证码\" maxlength=\"6\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><div style=\"display:flex;align-items:center;margin:16px 0\"><div style=\"flex:1;height:1px;background:var(--border)\"></div><span style=\"padding:0 12px;color:var(--text2);font-size:12px\">或</span><div style=\"flex:1;height:1px;background:var(--border)\"></div></div><button class=\"btn btn-ghost\" style=\"width:100%;display:flex;align-items:center;justify-content:center;gap:8px\" onclick=\"loginWithGithub()\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg> 使用 GitHub 登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();if(n.dataset.page==='workflows')loadWorkflowTemplates();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{\n// 先显示置顶的对话\nvar pinnedChats=chats.filter(function(c){return c.pinned});\nvar normalChats=chats.filter(function(c){return !c.pinned&&!c.archived});\nif(pinnedChats.length>0){html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2)\">📌 置顶</div>';pinnedChats.forEach(function(c){html+=renderChatItem(c)})}\nif(normalChats.length>0){if(pinnedChats.length>0)html+='<div style=\"padding:4px 12px;font-size:11px;color:var(--text2);margin-top:8px\">💬 对话</div>';normalChats.forEach(function(c){html+=renderChatItem(c)})}}$('chatList').innerHTML=html}\nfunction renderChatItem(c){var selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';var checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';var pinIcon=c.pinned?'📌':'💬';return'<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" style=\"'+selected+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">'+pinIcon+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var chat=chats.find(function(c){return c.id===id});var pinText=chat&&chat.pinned?'📌 取消置顶':'📌 置顶';var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"togglePinChat(\\''+id+'\\')\">'+pinText+'</div><div onclick=\"archiveChat(\\''+id+'\\')\">📦 归档</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction togglePinChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.pinned=!chat.pinned;saveChats();renderChats();showToast(chat.pinned?'已置顶':'已取消置顶');if(authToken){api('/api/conversations/'+id+'/pin',{method:'POST'}).catch(function(){})}}\nfunction archiveChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;chat.archived=true;chats=chats.filter(function(c){return c.id!==id});saveChats();renderChats();showToast('已归档');if(authToken){api('/api/conversations/'+id+'/archive',{method:'POST'}).catch(function(){})}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Agent 工作流\nvar workflowTemplates=[];\nvar currentWorkflow=null;\nfunction loadWorkflowTemplates(){api('/api/workflows/templates').then(function(data){workflowTemplates=data;renderWorkflowTemplates()}).catch(function(e){console.error('加载工作流失败:',e)})}\nfunction renderWorkflowTemplates(){var html=workflowTemplates.map(function(w){return'<div style=\"background:var(--bg);border-radius:12px;padding:20px;cursor:pointer\" onclick=\"selectWorkflow(\\''+w.id+'\\')\"><div style=\"display:flex;align-items:center;gap:12px;margin-bottom:12px\"><span style=\"font-size:24px\">🤖</span><div><strong>'+w.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+w.steps.length+' 个步骤</div></div></div><p style=\"font-size:13px;color:var(--text2);line-height:1.5\">'+w.description+'</p></div>'}).join('');$('workflowTemplates').innerHTML=html||'<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无工作流模板</div>'}\nfunction selectWorkflow(id){currentWorkflow=workflowTemplates.find(function(w){return w.id===id});if(!currentWorkflow)return;var inputs=[];currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')&&inputs.indexOf(key)===-1)inputs.push(key)})}});var html=inputs.map(function(key){return'<div class=\"form-group\"><label>'+key+'</label><textarea id=\"wf_'+key+'\" rows=\"3\" placeholder=\"输入 '+key+'\"></textarea></div>'}).join('');$('workflowInputs').innerHTML='<h5 style=\"margin-bottom:16px\">'+currentWorkflow.name+'</h5>'+html;$('workflowRunner').style.display='block';$('workflowResults').style.display='none'}\nfunction executeWorkflow(){if(!currentWorkflow){alert('请先选择工作流');return}var inputData={};currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')){var el=$('wf_'+key);if(el)inputData[key]=el.value}})}});$('workflowResultsContent').innerHTML='<div style=\"text-align:center;padding:40px\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px;color:var(--text2)\">正在执行工作流...</p></div>';$('workflowResults').style.display='block';api('/api/workflows/run',{method:'POST',body:JSON.stringify({name:currentWorkflow.name,steps:currentWorkflow.steps,input_data:inputData})}).then(function(data){var html='';for(var key in data.results){html+='<div style=\"background:var(--bg);border-radius:10px;padding:16px;margin-bottom:12px\"><div style=\"font-weight:600;margin-bottom:8px;color:var(--accent)\">'+key+'</div><div style=\"font-size:14px;line-height:1.6;white-space:pre-wrap\">'+data.results[key]+'</div></div>'}$('workflowResultsContent').innerHTML=html}).catch(function(e){$('workflowResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">执行失败: '+e.message+'</div>'})}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// GitHub 登录\nfunction loginWithGithub(){window.location.href='/api/auth/github'}\n// 2FA 设置\nfunction setup2FA(){if(!authToken){alert('请先登录');return}api('/api/auth/2fa/setup',{method:'POST'}).then(function(data){var html='<div style=\"text-align:center\"><img src=\"'+data.qr_code+'\" style=\"width:200px;height:200px;border-radius:8px\"><p style=\"margin:16px 0;color:var(--text2);font-size:13px\">使用 Google Authenticator 扫描二维码</p><div class=\"form-group\"><label>输入6位验证码确认</label><input type=\"text\" id=\"verify2FACode\" placeholder=\"000000\" maxlength=\"6\" style=\"text-align:center;font-size:20px;letter-spacing:8px\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"verify2FA()\">确认启用</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'2faModal\\')\">取消</button></div></div>';showCustomModal('设置双因素认证',html,'2faModal')}).catch(function(e){alert('设置失败: '+e.message)})}\nfunction verify2FA(){var code=$('verify2FACode').value.trim();if(code.length!==6){alert('请输入6位验证码');return}api('/api/auth/2fa/verify',{method:'POST',body:JSON.stringify({code:code})}).then(function(data){closeModal('2faModal');$('2faStatus').textContent='已启用';$('2faStatus').style.color='var(--success)';$('2faBtn').textContent='禁用';$('2faBtn').onclick=disable2FA;showToast('2FA 已启用')}).catch(function(e){alert('验证失败: '+e.message)})}\nfunction disable2FA(){var code=prompt('输入6位验证码以禁用 2FA:');if(!code)return;api('/api/auth/2fa/disable',{method:'POST',body:JSON.stringify({code:code})}).then(function(){$('2faStatus').textContent='未启用';$('2faStatus').style.color='var(--text2)';$('2faBtn').textContent='设置';$('2faBtn').onclick=setup2FA;showToast('2FA 已禁用')}).catch(function(e){alert('禁用失败: '+e.message)})}\nfunction showChangePasswordModal(){var html='<div class=\"form-group\"><label>当前密码</label><input type=\"password\" id=\"oldPassword\"></div><div class=\"form-group\"><label>新密码</label><input type=\"password\" id=\"newPassword\"></div><div class=\"form-group\"><label>确认新密码</label><input type=\"password\" id=\"confirmPassword\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"changePassword()\">修改</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pwdModal\\')\">取消</button></div>';showCustomModal('修改密码',html,'pwdModal')}\nfunction changePassword(){var oldPwd=$('oldPassword').value,newPwd=$('newPassword').value,confirmPwd=$('confirmPassword').value;if(!oldPwd||!newPwd){alert('请填写密码');return}if(newPwd!==confirmPwd){alert('两次密码不一致');return}alert('密码修改功能开发中')}\n// 检查 URL 中的 token(OAuth 回调)\n(function(){var params=new URLSearchParams(window.location.search);var token=params.get('token');if(token){localStorage.setItem('token',token);authToken=token;window.history.replaceState({},document.title,'/');checkAuth()}})();\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\n// 代码运行器\nfunction runCode(){var code=$('codeInput').value;var lang=$('codeLanguage').value;if(!code.trim()){alert('请输入代码');return}$('codeOutput').textContent='运行中...';$('codeOutput').style.color='var(--text2)';api('/api/code/run',{method:'POST',body:JSON.stringify({code:code,language:lang,timeout:5})}).then(function(data){if(data.success){$('codeOutput').textContent=data.output||'(无输出)';$('codeOutput').style.color='var(--success)'}else{$('codeOutput').textContent='错误: '+(data.error||'未知错误')+'\\n'+data.output;$('codeOutput').style.color='var(--error)'}}).catch(function(e){$('codeOutput').textContent='请求失败: '+e.message;$('codeOutput').style.color='var(--error)'})}\n// 思维导图\nfunction generateMindmap(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}showToast('正在生成思维导图...');api('/api/mindmap/generate',{method:'POST',body:JSON.stringify({messages:chat.messages,title:chat.title})}).then(function(data){renderMindmap(data.nodes)}).catch(function(e){alert('生成失败: '+e.message)})}\nfunction renderMindmap(nodes){var html='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.8);z-index:2000;display:flex;align-items:center;justify-content:center\" onclick=\"if(event.target===this)this.remove()\"><div style=\"background:var(--bg2);border-radius:16px;padding:24px;max-width:800px;max-height:80vh;overflow:auto\"><h3 style=\"margin-bottom:16px\">🧠 思维导图</h3><div id=\"mindmapContent\" style=\"padding:20px\"></div><button class=\"btn btn-ghost\" onclick=\"this.parentElement.parentElement.remove()\">关闭</button></div></div>';document.body.insertAdjacentHTML('beforeend',html);var content='';function renderNode(node,level){var indent=level*24;content+='<div style=\"margin-left:'+indent+'px;padding:8px 12px;margin-bottom:4px;background:var(--bg'+(level>0?'3':'')+');border-radius:6px;border-left:3px solid var(--accent)\">'+(level>0?'├─ ':'')+node.label+'</div>';if(node.children){node.children.forEach(function(c){renderNode(c,level+1)})}}if(nodes&&nodes.length)renderNode(nodes[0],0);$('mindmapContent').innerHTML=content||'<p style=\"color:var(--text2)\">无法生成思维导图</p>'}\n// 保存对话为模板\nfunction saveAsTemplate(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}var name=prompt('模板名称:',chat.title);if(!name)return;api('/api/chat-templates',{method:'POST',body:JSON.stringify({name:name,messages:chat.messages})}).then(function(){showToast('已保存为模板')}).catch(function(e){alert('保存失败: '+e.message)})}\n// 用量配额\nfunction loadQuota(){api('/api/quota').then(function(data){var html='<div style=\"margin-bottom:16px\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Token 使用量</span><span>'+formatNumber(data.tokens_used)+' / '+formatNumber(data.tokens_limit)+'</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;overflow:hidden\"><div style=\"background:var(--accent);height:100%;width:'+data.usage_percent+'%\"></div></div></div><p style=\"font-size:12px;color:var(--text2)\">当前套餐: '+data.plan+'</p>';if($('quotaInfo'))$('quotaInfo').innerHTML=html}).catch(function(e){console.error(e)})}\n// PWA 注册\nif('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js').then(function(reg){console.log('SW registered');if('Notification' in window&&Notification.permission==='default'){Notification.requestPermission()}}).catch(function(e){console.error('SW failed:',e)})}\n// 图片生成\nfunction generateImage(){var prompt=prompt('输入图片描述:');if(!prompt)return;showToast('正在生成图片...');api('/api/images/generate',{method:'POST',body:JSON.stringify({prompt:prompt})}).then(function(data){var img='<img src=\"'+data.url+'\" style=\"max-width:100%;border-radius:8px\">';var chat=chats.find(function(c){return c.id===currentChatId});if(chat){chat.messages.push({role:'assistant',content:'![生成的图片]('+data.url+')\\n\\n'+data.revised_prompt});saveChats();renderMessages()}showToast('图片已生成')}).catch(function(e){alert('生成失败: '+e.message)})}\n// TTS 语音合成\nfunction speakText(text){api('/api/audio/tts',{method:'POST',body:JSON.stringify({text:text,voice:'alloy'})}).then(function(data){var audio=new Audio(data.audio);audio.play();showToast('正在播放')}).catch(function(e){if('speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(text);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('TTS 失败: '+e.message)}})}\n// 内容过滤\nfunction filterContent(text){return api('/api/content/filter',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data})}\n// 数据脱敏\nfunction maskData(text){return api('/api/data/mask',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data.masked})}\n// 备份\nfunction createBackup(){api('/api/backup',{method:'POST'}).then(function(data){showToast('备份已创建: '+data.path)}).catch(function(e){alert('备份失败: '+e.message)})}\n// 离线检测\nwindow.addEventListener('online',function(){showToast('网络已恢复')});\nwindow.addEventListener('offline',function(){showToast('网络已断开,部分功能不可用')});\n\n// ========== 性能监控面板 ==========\nfunction showHealthDashboard(){\napi('/api/health/detailed').then(function(data){\nvar html='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">CPU 使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.cpu_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.cpu_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">内存使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.memory_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.memory_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">磁盘使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.disk_percent>90?'var(--error)':'var(--success)')+'\">'+data.system.disk_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">数据库延迟</div><div style=\"font-size:24px;font-weight:600;color:'+(data.components.database.latency_ms>100?'var(--warning)':'var(--success)')+'\">'+data.components.database.latency_ms+'ms</div></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:10px\">';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>缓存</span><span>'+data.components.cache.size+'/'+data.components.cache.max_size+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Redis</span><span style=\"color:'+(data.components.redis.status==='healthy'?'var(--success)':'var(--warning)')+'\">'+data.components.redis.status+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between\"><span>待处理任务</span><span>'+data.components.task_queue.pending_tasks+'</span></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;text-align:center;font-size:12px;color:var(--text2)\">版本 '+data.version+' · 运行时间 '+formatUptime(data.uptime_seconds)+'</div>';\nshowCustomModal('🖥️ 系统状态',html,'healthModal')\n}).catch(function(e){alert('获取状态失败: '+e.message)})}\nfunction formatUptime(seconds){var h=Math.floor(seconds/3600);var m=Math.floor((seconds%3600)/60);return h+'小时'+m+'分钟'}\n\n// ========== 批量操作 ==========\nvar batchMode=false;\nvar selectedChats=[];\nfunction toggleBatchMode(){batchMode=!batchMode;selectedChats=[];if(batchMode){$('batchActions').style.display='flex';showToast('已进入批量选择模式')}else{$('batchActions').style.display='none'}renderChatList()}\nfunction toggleChatSelection(id,e){if(!batchMode)return;e.stopPropagation();var idx=selectedChats.indexOf(id);if(idx>=0){selectedChats.splice(idx,1)}else{selectedChats.push(id)}renderChatList();$('selectedCount').textContent=selectedChats.length}\nfunction batchDeleteChats(){if(selectedChats.length===0){alert('请先选择对话');return}if(!confirm('确定删除 '+selectedChats.length+' 个对话?'))return;api('/api/conversations/batch-delete',{method:'POST',body:JSON.stringify({ids:selectedChats})}).then(function(data){showToast('已删除 '+data.deleted+' 个对话');selectedChats=[];batchMode=false;$('batchActions').style.display='none';loadChats()}).catch(function(e){alert('删除失败: '+e.message)})}\nfunction batchExportChats(){if(selectedChats.length===0){alert('请先选择对话');return}api('/api/messages/batch-export',{method:'POST',body:JSON.stringify({conversation_ids:selectedChats,format:'json'})}).then(function(data){var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='conversations_export.json';a.click();showToast('已导出 '+data.count+' 个对话')}).catch(function(e){alert('导出失败: '+e.message)})}\n\n// ========== 数据库优化 ==========\nfunction optimizeDatabase(){if(!confirm('确定要优化数据库?这将清理过期数据。'))return;showToast('正在优化...');api('/api/admin/optimize-db',{method:'POST'}).then(function(data){showToast(data.message)}).catch(function(e){alert('优化失败: '+e.message)})}\n\n// ========== 快捷键增强 ==========\ndocument.addEventListener('keydown',function(e){\nif(e.ctrlKey&&e.key==='h'){e.preventDefault();showHealthDashboard()}\nif(e.ctrlKey&&e.key==='b'){e.preventDefault();toggleBatchMode()}\nif(e.ctrlKey&&e.shiftKey&&e.key==='E'){e.preventDefault();batchExportChats()}\n});\n\n// ========== 性能优化:虚拟滚动 ==========\nfunction renderChatListVirtual(){\nvar container=$('chatList');\nvar itemHeight=60;\nvar visibleCount=Math.ceil(container.clientHeight/itemHeight)+2;\nvar scrollTop=container.scrollTop;\nvar startIndex=Math.floor(scrollTop/itemHeight);\nvar endIndex=Math.min(startIndex+visibleCount,chats.length);\nvar html='<div style=\"height:'+(startIndex*itemHeight)+'px\"></div>';\nfor(var i=startIndex;i<endIndex;i++){\nvar c=chats[i];\nvar active=c.id===currentChatId?'active':'';\nvar selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';\nvar checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';\nhtml+='<div class=\"sidebar-item '+active+'\" style=\"'+selected+'\" onclick=\"loadChat(\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+c.title+'</div><div class=\"sidebar-item-desc\">'+(c.messages.length||0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" style=\"opacity:0\" onclick=\"deleteChat(\\''+c.id+'\\',event)\">🗑️</button></div>'\n}\nhtml+='<div style=\"height:'+((chats.length-endIndex)*itemHeight)+'px\"></div>';\ncontainer.innerHTML=html}\n\n// ========== 请求重试机制 ==========\nasync function apiWithRetry(url,options,maxRetries=3){\nfor(var i=0;i<maxRetries;i++){\ntry{return await api(url,options)}\ncatch(e){\nif(i===maxRetries-1)throw e;\nawait new Promise(function(r){setTimeout(r,1000*(i+1))});\nconsole.log('Retrying request...',i+1)\n}}}\n\n// ========== 消息队列(离线支持) ==========\nvar offlineQueue=JSON.parse(localStorage.getItem('offlineQueue')||'[]');\nfunction queueOfflineMessage(msg){offlineQueue.push({msg:msg,time:Date.now()});localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))}\nfunction processOfflineQueue(){if(offlineQueue.length===0)return;showToast('正在发送离线消息...');var msg=offlineQueue.shift();localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue));sendMessageInternal(msg.msg).then(function(){processOfflineQueue()}).catch(function(){offlineQueue.unshift(msg);localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))})}\nwindow.addEventListener('online',processOfflineQueue);\n\n// ========== 智能预加载 ==========\nfunction preloadNextChat(){\nvar currentIdx=chats.findIndex(function(c){return c.id===currentChatId});\nif(currentIdx>=0&&currentIdx<chats.length-1){\nvar nextChat=chats[currentIdx+1];\nif(!nextChat.messages||nextChat.messages.length===0){\napi('/api/conversations/'+nextChat.id+'/messages').then(function(msgs){nextChat.messages=msgs})}}}\n\n// ========== 自动保存草稿 ==========\nvar draftTimer=null;\nfunction saveDraft(){var input=$('chatInput').value;if(input&&currentChatId){localStorage.setItem('draft_'+currentChatId,input)}}\nfunction loadDraft(){if(currentChatId){var draft=localStorage.getItem('draft_'+currentChatId);if(draft)$('chatInput').value=draft}}\nfunction clearDraft(){if(currentChatId)localStorage.removeItem('draft_'+currentChatId)}\n$('chatInput').addEventListener('input',function(){clearTimeout(draftTimer);draftTimer=setTimeout(saveDraft,1000)});\n\n// ========== 消息搜索增强 ==========\nfunction searchInCurrentChat(){var q=prompt('在当前对话中搜索:');if(!q)return;var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages)return;var results=chat.messages.filter(function(m){return m.content&&m.content.toLowerCase().includes(q.toLowerCase())});if(results.length===0){alert('未找到匹配消息');return}var html='<div style=\"max-height:400px;overflow-y:auto\">';results.forEach(function(m,i){html+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:4px\">'+(m.role==='user'?'👤 用户':'🤖 助手')+'</div><div style=\"font-size:14px\">'+m.content.slice(0,200)+(m.content.length>200?'...':'')+'</div></div>'});html+='</div>';showCustomModal('搜索结果 ('+results.length+')',html,'searchResultModal')}\n\n// ========== 快速回复 ==========\nvar quickReplies=[\n{id:'continue',text:'继续',prompt:'请继续'},\n{id:'explain',text:'解释',prompt:'请详细解释一下'},\n{id:'example',text:'举例',prompt:'请举个例子'},\n{id:'simplify',text:'简化',prompt:'请用更简单的语言解释'},\n{id:'code',text:'代码',prompt:'请给出代码示例'},\n{id:'summary',text:'总结',prompt:'请总结一下要点'}\n];\nfunction showQuickReplies(){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages||chat.messages.length===0){$('quickReplies').style.display='none';return}\nvar lastMsg=chat.messages[chat.messages.length-1];\nif(lastMsg.role!=='assistant'){$('quickReplies').style.display='none';return}\nvar html=quickReplies.map(function(r){return'<button class=\"btn btn-ghost btn-sm\" onclick=\"sendQuickReply(\\''+r.prompt+'\\')\">'+r.text+'</button>'}).join('');\n$('quickReplies').innerHTML=html;\n$('quickReplies').style.display='flex'}\nfunction sendQuickReply(prompt){$('chatInput').value=prompt;sendMessage()}\n\n// ========== 数据导入导出 ==========\nfunction exportAllData(){\nif(!authToken){alert('请先登录');return}\nshowToast('正在导出数据...');\napi('/api/data/export-all',{method:'POST'}).then(function(data){\nvar blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='ai_hub_backup_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})}\n\nfunction importAllData(){\nif(!authToken){alert('请先登录');return}\nvar input=document.createElement('input');\ninput.type='file';\ninput.accept='.json';\ninput.onchange=function(e){\nvar file=e.target.files[0];\nif(!file)return;\nvar reader=new FileReader();\nreader.onload=function(ev){\ntry{\nvar data=JSON.parse(ev.target.result);\nif(!confirm('确定要导入数据?这将添加 '+\n(data.conversations?data.conversations.length:0)+' 个对话、'+\n(data.notes?data.notes.length:0)+' 个笔记'))return;\napi('/api/data/import',{method:'POST',body:JSON.stringify(data)}).then(function(result){\nshowToast('导入完成: '+result.imported.conversations+' 对话, '+result.imported.notes+' 笔记');\nloadChats()\n}).catch(function(e){alert('导入失败: '+e.message)})\n}catch(e){alert('文件格式错误')}};\nreader.readAsText(file)};\ninput.click()}\n\n// ========== 智能推荐 ==========\nfunction loadRecommendations(){\napi('/api/recommendations').then(function(data){\nif(data.features&&data.features.length>0){\nvar html='<div style=\"padding:16px;background:var(--bg3);border-radius:10px;margin-bottom:16px\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:12px\">💡 推荐功能</div><div style=\"display:flex;gap:12px;flex-wrap:wrap\">';\ndata.features.forEach(function(f){\nhtml+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;cursor:pointer;flex:1;min-width:150px\" onclick=\"showFeatureGuide(\\''+f.name+'\\')\"><span style=\"font-size:20px\">'+f.icon+'</span><div style=\"font-size:14px;font-weight:500;margin-top:8px\">'+f.name+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+f.desc+'</div></div>'});\nhtml+='</div></div>';\nvar container=$('chatMessages');\nif(container&&container.querySelector('.empty-state')){\ncontainer.innerHTML=html+container.innerHTML}}\n}).catch(function(){})}\nfunction showFeatureGuide(name){\nvar guides={\n'知识库':'点击左侧导航的\"知识库\",创建知识库并上传文档,AI 将基于您的资料回答问题。',\n'团队协作':'点击左侧导航的\"团队空间\",创建团队并邀请成员,共享对话和资源。'\n};\nalert(guides[name]||'功能介绍开发中')}\n\n// ========== 收藏消息 ==========\nfunction favoriteMessage(content){\nif(!authToken){alert('请先登录');return}\napi('/api/messages/favorite',{method:'POST',body:JSON.stringify({\nconversation_id:currentChatId,\ncontent:content\n})}).then(function(){showToast('已收藏到记忆')}).catch(function(e){alert('收藏失败: '+e.message)})}\n\n// ========== 使用分析 ==========\nfunction showUsageAnalytics(){\napi('/api/analytics/usage?days=30').then(function(data){\nvar html='<div style=\"margin-bottom:20px\"><h4 style=\"margin-bottom:12px\">📊 30天使用趋势</h4>';\nif(data.daily_usage.length>0){\nvar maxCalls=Math.max.apply(null,data.daily_usage.map(function(d){return d.calls}));\nhtml+='<div style=\"display:flex;align-items:flex-end;gap:4px;height:100px\">';\ndata.daily_usage.forEach(function(d){\nvar height=Math.max(5,(d.calls/maxCalls)*100);\nhtml+='<div style=\"flex:1;background:var(--accent);border-radius:2px 2px 0 0;height:'+height+'px\" title=\"'+d.day+': '+d.calls+'次\"></div>'});\nhtml+='</div>'}\nhtml+='</div>';\nhtml+='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">总调用次数</div><div style=\"font-size:24px;font-weight:600\">'+data.total_calls+'</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">错误率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.error_rate>5?'var(--error)':'var(--success)')+'\">'+data.error_rate+'%</div></div>';\nhtml+='</div>';\nshowCustomModal('📈 使用分析',html,'analyticsModal')\n}).catch(function(e){alert('获取分析失败: '+e.message)})}\n\n// 初始化时加载推荐\nsetTimeout(loadRecommendations,1000);\n\nconsole.log('🤖 AI Hub v2.0.0 - Enhanced');\n</script>\n</body>\n</html>\n"}, "ec92949cc1fe70b147ecb564c1710429afca490f": {"t": 1785765471.3147259, "n": 204387, "h": "d6af544fbe19e6fe", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"theme-color\" content=\"#0f0f1a\">\n<meta name=\"description\" content=\"AI Hub - 统一 AI 平台\">\n<link rel=\"manifest\" href=\"/static/manifest.json\">\n<link rel=\"apple-touch-icon\" href=\"/static/icon-192.png\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"workflows\"><span class=\"nav-item-icon\">🤖</span> Agent 工作流</div>\n<div class=\"nav-item\" data-page=\"code-runner\"><span class=\"nav-item-icon\">▶️</span> 代码运行</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" onclick=\"showHealthDashboard()\"><span class=\"nav-item-icon\">🖥️</span> 系统状态</div>\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\" title=\"批量操作\">☑️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div id=\"batchActions\" style=\"display:none;padding:8px;background:var(--bg3);gap:8px;align-items:center\">\n<span style=\"font-size:12px\">已选 <span id=\"selectedCount\">0</span> 个</span>\n<button class=\"btn btn-danger btn-sm\" onclick=\"batchDeleteChats()\">删除</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"batchExportChats()\">导出</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\">取消</button>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"quickReplies\" style=\"display:none;padding:8px 0;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap\"></div>\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateImage()\" title=\"生成图片\">🎨</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateMindmap()\" title=\"生成思维导图\">🧠</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"saveAsTemplate()\" title=\"保存为模板\">💾</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">双因素认证 (2FA)<br><small style=\"color:var(--text2)\">使用 Google Authenticator 等应用增强账户安全</small></div><div style=\"display:flex;gap:8px\"><span id=\"2faStatus\" style=\"color:var(--text2)\">未启用</span><button class=\"btn btn-ghost btn-sm\" onclick=\"setup2FA()\" id=\"2faBtn\">设置</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录设备管理</div><button class=\"btn btn-ghost btn-sm\" onclick=\"alert('功能开发中')\">查看设备</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">修改密码</div><button class=\"btn btn-ghost btn-sm\" onclick=\"showChangePasswordModal()\">修改</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复<br><small style=\"color:var(--text2)\">导出/导入所有数据(对话、笔记、记忆、设置)</small></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-primary\" onclick=\"exportAllData()\">📤 导出全部</button><button class=\"btn btn-ghost\" onclick=\"importAllData()\">📥 导入数据</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据库优化<br><small style=\"color:var(--text2)\">清理过期数据,优化数据库性能</small></div><button class=\"btn btn-ghost\" onclick=\"optimizeDatabase()\">🔧 优化数据库</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n<button class=\"btn btn-primary\" onclick=\"showUsageAnalytics()\">📈 详细分析</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Agent 工作流页 -->\n<div id=\"page-workflows\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🤖</span> Agent 工作流</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建多步骤自动化任务,让 AI 按流程完成复杂工作</p>\n<div id=\"workflowTemplates\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px\"></div>\n</div>\n<div class=\"settings-section\" id=\"workflowRunner\" style=\"display:none\">\n<h4><span>▶️</span> 运行工作流</h4>\n<div id=\"workflowInputs\"></div>\n<button class=\"btn btn-primary\" onclick=\"executeWorkflow()\">🚀 执行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('workflowRunner').style.display='none'\">取消</button>\n</div>\n<div class=\"settings-section\" id=\"workflowResults\" style=\"display:none\">\n<h4><span>📋</span> 执行结果</h4>\n<div id=\"workflowResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 代码运行器页 -->\n<div id=\"page-code-runner\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>▶️</span> 代码运行器</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">在线运行 Python / JavaScript 代码</p>\n<div class=\"form-group\">\n<label>语言</label>\n<select id=\"codeLanguage\" style=\"width:150px\">\n<option value=\"python\">Python</option>\n<option value=\"javascript\">JavaScript</option>\n</select>\n</div>\n<div class=\"form-group\">\n<label>代码</label>\n<textarea id=\"codeInput\" rows=\"12\" style=\"font-family:monospace;font-size:13px\" placeholder=\"# 输入代码...\nprint('Hello, World!')\"></textarea>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-primary\" onclick=\"runCode()\">▶️ 运行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('codeInput').value=''\">清空</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 输出结果</h4>\n<pre id=\"codeOutput\" style=\"background:var(--bg);padding:16px;border-radius:8px;min-height:100px;font-family:monospace;font-size:13px;white-space:pre-wrap\">等待运行...</pre>\n</div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><div class=\"form-group\" id=\"auth2FAGroup\" style=\"display:none\"><label>2FA 验证码</label><input type=\"text\" id=\"auth2FACode\" placeholder=\"6位验证码\" maxlength=\"6\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><div style=\"display:flex;align-items:center;margin:16px 0\"><div style=\"flex:1;height:1px;background:var(--border)\"></div><span style=\"padding:0 12px;color:var(--text2);font-size:12px\">或</span><div style=\"flex:1;height:1px;background:var(--border)\"></div></div><button class=\"btn btn-ghost\" style=\"width:100%;display:flex;align-items:center;justify-content:center;gap:8px\" onclick=\"loginWithGithub()\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg> 使用 GitHub 登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();if(n.dataset.page==='workflows')loadWorkflowTemplates();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Agent 工作流\nvar workflowTemplates=[];\nvar currentWorkflow=null;\nfunction loadWorkflowTemplates(){api('/api/workflows/templates').then(function(data){workflowTemplates=data;renderWorkflowTemplates()}).catch(function(e){console.error('加载工作流失败:',e)})}\nfunction renderWorkflowTemplates(){var html=workflowTemplates.map(function(w){return'<div style=\"background:var(--bg);border-radius:12px;padding:20px;cursor:pointer\" onclick=\"selectWorkflow(\\''+w.id+'\\')\"><div style=\"display:flex;align-items:center;gap:12px;margin-bottom:12px\"><span style=\"font-size:24px\">🤖</span><div><strong>'+w.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+w.steps.length+' 个步骤</div></div></div><p style=\"font-size:13px;color:var(--text2);line-height:1.5\">'+w.description+'</p></div>'}).join('');$('workflowTemplates').innerHTML=html||'<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无工作流模板</div>'}\nfunction selectWorkflow(id){currentWorkflow=workflowTemplates.find(function(w){return w.id===id});if(!currentWorkflow)return;var inputs=[];currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')&&inputs.indexOf(key)===-1)inputs.push(key)})}});var html=inputs.map(function(key){return'<div class=\"form-group\"><label>'+key+'</label><textarea id=\"wf_'+key+'\" rows=\"3\" placeholder=\"输入 '+key+'\"></textarea></div>'}).join('');$('workflowInputs').innerHTML='<h5 style=\"margin-bottom:16px\">'+currentWorkflow.name+'</h5>'+html;$('workflowRunner').style.display='block';$('workflowResults').style.display='none'}\nfunction executeWorkflow(){if(!currentWorkflow){alert('请先选择工作流');return}var inputData={};currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')){var el=$('wf_'+key);if(el)inputData[key]=el.value}})}});$('workflowResultsContent').innerHTML='<div style=\"text-align:center;padding:40px\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px;color:var(--text2)\">正在执行工作流...</p></div>';$('workflowResults').style.display='block';api('/api/workflows/run',{method:'POST',body:JSON.stringify({name:currentWorkflow.name,steps:currentWorkflow.steps,input_data:inputData})}).then(function(data){var html='';for(var key in data.results){html+='<div style=\"background:var(--bg);border-radius:10px;padding:16px;margin-bottom:12px\"><div style=\"font-weight:600;margin-bottom:8px;color:var(--accent)\">'+key+'</div><div style=\"font-size:14px;line-height:1.6;white-space:pre-wrap\">'+data.results[key]+'</div></div>'}$('workflowResultsContent').innerHTML=html}).catch(function(e){$('workflowResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">执行失败: '+e.message+'</div>'})}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// GitHub 登录\nfunction loginWithGithub(){window.location.href='/api/auth/github'}\n// 2FA 设置\nfunction setup2FA(){if(!authToken){alert('请先登录');return}api('/api/auth/2fa/setup',{method:'POST'}).then(function(data){var html='<div style=\"text-align:center\"><img src=\"'+data.qr_code+'\" style=\"width:200px;height:200px;border-radius:8px\"><p style=\"margin:16px 0;color:var(--text2);font-size:13px\">使用 Google Authenticator 扫描二维码</p><div class=\"form-group\"><label>输入6位验证码确认</label><input type=\"text\" id=\"verify2FACode\" placeholder=\"000000\" maxlength=\"6\" style=\"text-align:center;font-size:20px;letter-spacing:8px\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"verify2FA()\">确认启用</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'2faModal\\')\">取消</button></div></div>';showCustomModal('设置双因素认证',html,'2faModal')}).catch(function(e){alert('设置失败: '+e.message)})}\nfunction verify2FA(){var code=$('verify2FACode').value.trim();if(code.length!==6){alert('请输入6位验证码');return}api('/api/auth/2fa/verify',{method:'POST',body:JSON.stringify({code:code})}).then(function(data){closeModal('2faModal');$('2faStatus').textContent='已启用';$('2faStatus').style.color='var(--success)';$('2faBtn').textContent='禁用';$('2faBtn').onclick=disable2FA;showToast('2FA 已启用')}).catch(function(e){alert('验证失败: '+e.message)})}\nfunction disable2FA(){var code=prompt('输入6位验证码以禁用 2FA:');if(!code)return;api('/api/auth/2fa/disable',{method:'POST',body:JSON.stringify({code:code})}).then(function(){$('2faStatus').textContent='未启用';$('2faStatus').style.color='var(--text2)';$('2faBtn').textContent='设置';$('2faBtn').onclick=setup2FA;showToast('2FA 已禁用')}).catch(function(e){alert('禁用失败: '+e.message)})}\nfunction showChangePasswordModal(){var html='<div class=\"form-group\"><label>当前密码</label><input type=\"password\" id=\"oldPassword\"></div><div class=\"form-group\"><label>新密码</label><input type=\"password\" id=\"newPassword\"></div><div class=\"form-group\"><label>确认新密码</label><input type=\"password\" id=\"confirmPassword\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"changePassword()\">修改</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pwdModal\\')\">取消</button></div>';showCustomModal('修改密码',html,'pwdModal')}\nfunction changePassword(){var oldPwd=$('oldPassword').value,newPwd=$('newPassword').value,confirmPwd=$('confirmPassword').value;if(!oldPwd||!newPwd){alert('请填写密码');return}if(newPwd!==confirmPwd){alert('两次密码不一致');return}alert('密码修改功能开发中')}\n// 检查 URL 中的 token(OAuth 回调)\n(function(){var params=new URLSearchParams(window.location.search);var token=params.get('token');if(token){localStorage.setItem('token',token);authToken=token;window.history.replaceState({},document.title,'/');checkAuth()}})();\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\n// 代码运行器\nfunction runCode(){var code=$('codeInput').value;var lang=$('codeLanguage').value;if(!code.trim()){alert('请输入代码');return}$('codeOutput').textContent='运行中...';$('codeOutput').style.color='var(--text2)';api('/api/code/run',{method:'POST',body:JSON.stringify({code:code,language:lang,timeout:5})}).then(function(data){if(data.success){$('codeOutput').textContent=data.output||'(无输出)';$('codeOutput').style.color='var(--success)'}else{$('codeOutput').textContent='错误: '+(data.error||'未知错误')+'\\n'+data.output;$('codeOutput').style.color='var(--error)'}}).catch(function(e){$('codeOutput').textContent='请求失败: '+e.message;$('codeOutput').style.color='var(--error)'})}\n// 思维导图\nfunction generateMindmap(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}showToast('正在生成思维导图...');api('/api/mindmap/generate',{method:'POST',body:JSON.stringify({messages:chat.messages,title:chat.title})}).then(function(data){renderMindmap(data.nodes)}).catch(function(e){alert('生成失败: '+e.message)})}\nfunction renderMindmap(nodes){var html='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.8);z-index:2000;display:flex;align-items:center;justify-content:center\" onclick=\"if(event.target===this)this.remove()\"><div style=\"background:var(--bg2);border-radius:16px;padding:24px;max-width:800px;max-height:80vh;overflow:auto\"><h3 style=\"margin-bottom:16px\">🧠 思维导图</h3><div id=\"mindmapContent\" style=\"padding:20px\"></div><button class=\"btn btn-ghost\" onclick=\"this.parentElement.parentElement.remove()\">关闭</button></div></div>';document.body.insertAdjacentHTML('beforeend',html);var content='';function renderNode(node,level){var indent=level*24;content+='<div style=\"margin-left:'+indent+'px;padding:8px 12px;margin-bottom:4px;background:var(--bg'+(level>0?'3':'')+');border-radius:6px;border-left:3px solid var(--accent)\">'+(level>0?'├─ ':'')+node.label+'</div>';if(node.children){node.children.forEach(function(c){renderNode(c,level+1)})}}if(nodes&&nodes.length)renderNode(nodes[0],0);$('mindmapContent').innerHTML=content||'<p style=\"color:var(--text2)\">无法生成思维导图</p>'}\n// 保存对话为模板\nfunction saveAsTemplate(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}var name=prompt('模板名称:',chat.title);if(!name)return;api('/api/chat-templates',{method:'POST',body:JSON.stringify({name:name,messages:chat.messages})}).then(function(){showToast('已保存为模板')}).catch(function(e){alert('保存失败: '+e.message)})}\n// 用量配额\nfunction loadQuota(){api('/api/quota').then(function(data){var html='<div style=\"margin-bottom:16px\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Token 使用量</span><span>'+formatNumber(data.tokens_used)+' / '+formatNumber(data.tokens_limit)+'</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;overflow:hidden\"><div style=\"background:var(--accent);height:100%;width:'+data.usage_percent+'%\"></div></div></div><p style=\"font-size:12px;color:var(--text2)\">当前套餐: '+data.plan+'</p>';if($('quotaInfo'))$('quotaInfo').innerHTML=html}).catch(function(e){console.error(e)})}\n// PWA 注册\nif('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js').then(function(reg){console.log('SW registered');if('Notification' in window&&Notification.permission==='default'){Notification.requestPermission()}}).catch(function(e){console.error('SW failed:',e)})}\n// 图片生成\nfunction generateImage(){var prompt=prompt('输入图片描述:');if(!prompt)return;showToast('正在生成图片...');api('/api/images/generate',{method:'POST',body:JSON.stringify({prompt:prompt})}).then(function(data){var img='<img src=\"'+data.url+'\" style=\"max-width:100%;border-radius:8px\">';var chat=chats.find(function(c){return c.id===currentChatId});if(chat){chat.messages.push({role:'assistant',content:'![生成的图片]('+data.url+')\\n\\n'+data.revised_prompt});saveChats();renderMessages()}showToast('图片已生成')}).catch(function(e){alert('生成失败: '+e.message)})}\n// TTS 语音合成\nfunction speakText(text){api('/api/audio/tts',{method:'POST',body:JSON.stringify({text:text,voice:'alloy'})}).then(function(data){var audio=new Audio(data.audio);audio.play();showToast('正在播放')}).catch(function(e){if('speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(text);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('TTS 失败: '+e.message)}})}\n// 内容过滤\nfunction filterContent(text){return api('/api/content/filter',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data})}\n// 数据脱敏\nfunction maskData(text){return api('/api/data/mask',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data.masked})}\n// 备份\nfunction createBackup(){api('/api/backup',{method:'POST'}).then(function(data){showToast('备份已创建: '+data.path)}).catch(function(e){alert('备份失败: '+e.message)})}\n// 离线检测\nwindow.addEventListener('online',function(){showToast('网络已恢复')});\nwindow.addEventListener('offline',function(){showToast('网络已断开,部分功能不可用')});\n\n// ========== 性能监控面板 ==========\nfunction showHealthDashboard(){\napi('/api/health/detailed').then(function(data){\nvar html='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">CPU 使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.cpu_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.cpu_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">内存使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.memory_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.memory_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">磁盘使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.disk_percent>90?'var(--error)':'var(--success)')+'\">'+data.system.disk_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">数据库延迟</div><div style=\"font-size:24px;font-weight:600;color:'+(data.components.database.latency_ms>100?'var(--warning)':'var(--success)')+'\">'+data.components.database.latency_ms+'ms</div></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:10px\">';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>缓存</span><span>'+data.components.cache.size+'/'+data.components.cache.max_size+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Redis</span><span style=\"color:'+(data.components.redis.status==='healthy'?'var(--success)':'var(--warning)')+'\">'+data.components.redis.status+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between\"><span>待处理任务</span><span>'+data.components.task_queue.pending_tasks+'</span></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;text-align:center;font-size:12px;color:var(--text2)\">版本 '+data.version+' · 运行时间 '+formatUptime(data.uptime_seconds)+'</div>';\nshowCustomModal('🖥️ 系统状态',html,'healthModal')\n}).catch(function(e){alert('获取状态失败: '+e.message)})}\nfunction formatUptime(seconds){var h=Math.floor(seconds/3600);var m=Math.floor((seconds%3600)/60);return h+'小时'+m+'分钟'}\n\n// ========== 批量操作 ==========\nvar batchMode=false;\nvar selectedChats=[];\nfunction toggleBatchMode(){batchMode=!batchMode;selectedChats=[];if(batchMode){$('batchActions').style.display='flex';showToast('已进入批量选择模式')}else{$('batchActions').style.display='none'}renderChatList()}\nfunction toggleChatSelection(id,e){if(!batchMode)return;e.stopPropagation();var idx=selectedChats.indexOf(id);if(idx>=0){selectedChats.splice(idx,1)}else{selectedChats.push(id)}renderChatList();$('selectedCount').textContent=selectedChats.length}\nfunction batchDeleteChats(){if(selectedChats.length===0){alert('请先选择对话');return}if(!confirm('确定删除 '+selectedChats.length+' 个对话?'))return;api('/api/conversations/batch-delete',{method:'POST',body:JSON.stringify({ids:selectedChats})}).then(function(data){showToast('已删除 '+data.deleted+' 个对话');selectedChats=[];batchMode=false;$('batchActions').style.display='none';loadChats()}).catch(function(e){alert('删除失败: '+e.message)})}\nfunction batchExportChats(){if(selectedChats.length===0){alert('请先选择对话');return}api('/api/messages/batch-export',{method:'POST',body:JSON.stringify({conversation_ids:selectedChats,format:'json'})}).then(function(data){var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='conversations_export.json';a.click();showToast('已导出 '+data.count+' 个对话')}).catch(function(e){alert('导出失败: '+e.message)})}\n\n// ========== 数据库优化 ==========\nfunction optimizeDatabase(){if(!confirm('确定要优化数据库?这将清理过期数据。'))return;showToast('正在优化...');api('/api/admin/optimize-db',{method:'POST'}).then(function(data){showToast(data.message)}).catch(function(e){alert('优化失败: '+e.message)})}\n\n// ========== 快捷键增强 ==========\ndocument.addEventListener('keydown',function(e){\nif(e.ctrlKey&&e.key==='h'){e.preventDefault();showHealthDashboard()}\nif(e.ctrlKey&&e.key==='b'){e.preventDefault();toggleBatchMode()}\nif(e.ctrlKey&&e.shiftKey&&e.key==='E'){e.preventDefault();batchExportChats()}\n});\n\n// ========== 性能优化:虚拟滚动 ==========\nfunction renderChatListVirtual(){\nvar container=$('chatList');\nvar itemHeight=60;\nvar visibleCount=Math.ceil(container.clientHeight/itemHeight)+2;\nvar scrollTop=container.scrollTop;\nvar startIndex=Math.floor(scrollTop/itemHeight);\nvar endIndex=Math.min(startIndex+visibleCount,chats.length);\nvar html='<div style=\"height:'+(startIndex*itemHeight)+'px\"></div>';\nfor(var i=startIndex;i<endIndex;i++){\nvar c=chats[i];\nvar active=c.id===currentChatId?'active':'';\nvar selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';\nvar checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';\nhtml+='<div class=\"sidebar-item '+active+'\" style=\"'+selected+'\" onclick=\"loadChat(\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+c.title+'</div><div class=\"sidebar-item-desc\">'+(c.messages.length||0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" style=\"opacity:0\" onclick=\"deleteChat(\\''+c.id+'\\',event)\">🗑️</button></div>'\n}\nhtml+='<div style=\"height:'+((chats.length-endIndex)*itemHeight)+'px\"></div>';\ncontainer.innerHTML=html}\n\n// ========== 请求重试机制 ==========\nasync function apiWithRetry(url,options,maxRetries=3){\nfor(var i=0;i<maxRetries;i++){\ntry{return await api(url,options)}\ncatch(e){\nif(i===maxRetries-1)throw e;\nawait new Promise(function(r){setTimeout(r,1000*(i+1))});\nconsole.log('Retrying request...',i+1)\n}}}\n\n// ========== 消息队列(离线支持) ==========\nvar offlineQueue=JSON.parse(localStorage.getItem('offlineQueue')||'[]');\nfunction queueOfflineMessage(msg){offlineQueue.push({msg:msg,time:Date.now()});localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))}\nfunction processOfflineQueue(){if(offlineQueue.length===0)return;showToast('正在发送离线消息...');var msg=offlineQueue.shift();localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue));sendMessageInternal(msg.msg).then(function(){processOfflineQueue()}).catch(function(){offlineQueue.unshift(msg);localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))})}\nwindow.addEventListener('online',processOfflineQueue);\n\n// ========== 智能预加载 ==========\nfunction preloadNextChat(){\nvar currentIdx=chats.findIndex(function(c){return c.id===currentChatId});\nif(currentIdx>=0&&currentIdx<chats.length-1){\nvar nextChat=chats[currentIdx+1];\nif(!nextChat.messages||nextChat.messages.length===0){\napi('/api/conversations/'+nextChat.id+'/messages').then(function(msgs){nextChat.messages=msgs})}}}\n\n// ========== 自动保存草稿 ==========\nvar draftTimer=null;\nfunction saveDraft(){var input=$('chatInput').value;if(input&&currentChatId){localStorage.setItem('draft_'+currentChatId,input)}}\nfunction loadDraft(){if(currentChatId){var draft=localStorage.getItem('draft_'+currentChatId);if(draft)$('chatInput').value=draft}}\nfunction clearDraft(){if(currentChatId)localStorage.removeItem('draft_'+currentChatId)}\n$('chatInput').addEventListener('input',function(){clearTimeout(draftTimer);draftTimer=setTimeout(saveDraft,1000)});\n\n// ========== 消息搜索增强 ==========\nfunction searchInCurrentChat(){var q=prompt('在当前对话中搜索:');if(!q)return;var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages)return;var results=chat.messages.filter(function(m){return m.content&&m.content.toLowerCase().includes(q.toLowerCase())});if(results.length===0){alert('未找到匹配消息');return}var html='<div style=\"max-height:400px;overflow-y:auto\">';results.forEach(function(m,i){html+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:4px\">'+(m.role==='user'?'👤 用户':'🤖 助手')+'</div><div style=\"font-size:14px\">'+m.content.slice(0,200)+(m.content.length>200?'...':'')+'</div></div>'});html+='</div>';showCustomModal('搜索结果 ('+results.length+')',html,'searchResultModal')}\n\n// ========== 快速回复 ==========\nvar quickReplies=[\n{id:'continue',text:'继续',prompt:'请继续'},\n{id:'explain',text:'解释',prompt:'请详细解释一下'},\n{id:'example',text:'举例',prompt:'请举个例子'},\n{id:'simplify',text:'简化',prompt:'请用更简单的语言解释'},\n{id:'code',text:'代码',prompt:'请给出代码示例'},\n{id:'summary',text:'总结',prompt:'请总结一下要点'}\n];\nfunction showQuickReplies(){\nvar chat=chats.find(function(c){return c.id===currentChatId});\nif(!chat||!chat.messages||chat.messages.length===0){$('quickReplies').style.display='none';return}\nvar lastMsg=chat.messages[chat.messages.length-1];\nif(lastMsg.role!=='assistant'){$('quickReplies').style.display='none';return}\nvar html=quickReplies.map(function(r){return'<button class=\"btn btn-ghost btn-sm\" onclick=\"sendQuickReply(\\''+r.prompt+'\\')\">'+r.text+'</button>'}).join('');\n$('quickReplies').innerHTML=html;\n$('quickReplies').style.display='flex'}\nfunction sendQuickReply(prompt){$('chatInput').value=prompt;sendMessage()}\n\n// ========== 数据导入导出 ==========\nfunction exportAllData(){\nif(!authToken){alert('请先登录');return}\nshowToast('正在导出数据...');\napi('/api/data/export-all',{method:'POST'}).then(function(data){\nvar blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});\nvar a=document.createElement('a');\na.href=URL.createObjectURL(blob);\na.download='ai_hub_backup_'+new Date().toISOString().slice(0,10)+'.json';\na.click();\nshowToast('数据已导出')\n}).catch(function(e){alert('导出失败: '+e.message)})}\n\nfunction importAllData(){\nif(!authToken){alert('请先登录');return}\nvar input=document.createElement('input');\ninput.type='file';\ninput.accept='.json';\ninput.onchange=function(e){\nvar file=e.target.files[0];\nif(!file)return;\nvar reader=new FileReader();\nreader.onload=function(ev){\ntry{\nvar data=JSON.parse(ev.target.result);\nif(!confirm('确定要导入数据?这将添加 '+\n(data.conversations?data.conversations.length:0)+' 个对话、'+\n(data.notes?data.notes.length:0)+' 个笔记'))return;\napi('/api/data/import',{method:'POST',body:JSON.stringify(data)}).then(function(result){\nshowToast('导入完成: '+result.imported.conversations+' 对话, '+result.imported.notes+' 笔记');\nloadChats()\n}).catch(function(e){alert('导入失败: '+e.message)})\n}catch(e){alert('文件格式错误')}};\nreader.readAsText(file)};\ninput.click()}\n\n// ========== 智能推荐 ==========\nfunction loadRecommendations(){\napi('/api/recommendations').then(function(data){\nif(data.features&&data.features.length>0){\nvar html='<div style=\"padding:16px;background:var(--bg3);border-radius:10px;margin-bottom:16px\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:12px\">💡 推荐功能</div><div style=\"display:flex;gap:12px;flex-wrap:wrap\">';\ndata.features.forEach(function(f){\nhtml+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;cursor:pointer;flex:1;min-width:150px\" onclick=\"showFeatureGuide(\\''+f.name+'\\')\"><span style=\"font-size:20px\">'+f.icon+'</span><div style=\"font-size:14px;font-weight:500;margin-top:8px\">'+f.name+'</div><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+f.desc+'</div></div>'});\nhtml+='</div></div>';\nvar container=$('chatMessages');\nif(container&&container.querySelector('.empty-state')){\ncontainer.innerHTML=html+container.innerHTML}}\n}).catch(function(){})}\nfunction showFeatureGuide(name){\nvar guides={\n'知识库':'点击左侧导航的\"知识库\",创建知识库并上传文档,AI 将基于您的资料回答问题。',\n'团队协作':'点击左侧导航的\"团队空间\",创建团队并邀请成员,共享对话和资源。'\n};\nalert(guides[name]||'功能介绍开发中')}\n\n// ========== 收藏消息 ==========\nfunction favoriteMessage(content){\nif(!authToken){alert('请先登录');return}\napi('/api/messages/favorite',{method:'POST',body:JSON.stringify({\nconversation_id:currentChatId,\ncontent:content\n})}).then(function(){showToast('已收藏到记忆')}).catch(function(e){alert('收藏失败: '+e.message)})}\n\n// ========== 使用分析 ==========\nfunction showUsageAnalytics(){\napi('/api/analytics/usage?days=30').then(function(data){\nvar html='<div style=\"margin-bottom:20px\"><h4 style=\"margin-bottom:12px\">📊 30天使用趋势</h4>';\nif(data.daily_usage.length>0){\nvar maxCalls=Math.max.apply(null,data.daily_usage.map(function(d){return d.calls}));\nhtml+='<div style=\"display:flex;align-items:flex-end;gap:4px;height:100px\">';\ndata.daily_usage.forEach(function(d){\nvar height=Math.max(5,(d.calls/maxCalls)*100);\nhtml+='<div style=\"flex:1;background:var(--accent);border-radius:2px 2px 0 0;height:'+height+'px\" title=\"'+d.day+': '+d.calls+'次\"></div>'});\nhtml+='</div>'}\nhtml+='</div>';\nhtml+='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">总调用次数</div><div style=\"font-size:24px;font-weight:600\">'+data.total_calls+'</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">错误率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.error_rate>5?'var(--error)':'var(--success)')+'\">'+data.error_rate+'%</div></div>';\nhtml+='</div>';\nshowCustomModal('📈 使用分析',html,'analyticsModal')\n}).catch(function(e){alert('获取分析失败: '+e.message)})}\n\n// 初始化时加载推荐\nsetTimeout(loadRecommendations,1000);\n\nconsole.log('🤖 AI Hub v2.0.0 - Enhanced');\n</script>\n</body>\n</html>\n"}, "84dfee8ffa42e983b7adad704f7b4a1752a0c1b4": {"t": 1785765473.2806427, "n": 198845, "h": "9b7593e37d37fd1a", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"theme-color\" content=\"#0f0f1a\">\n<meta name=\"description\" content=\"AI Hub - 统一 AI 平台\">\n<link rel=\"manifest\" href=\"/static/manifest.json\">\n<link rel=\"apple-touch-icon\" href=\"/static/icon-192.png\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"workflows\"><span class=\"nav-item-icon\">🤖</span> Agent 工作流</div>\n<div class=\"nav-item\" data-page=\"code-runner\"><span class=\"nav-item-icon\">▶️</span> 代码运行</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" onclick=\"showHealthDashboard()\"><span class=\"nav-item-icon\">🖥️</span> 系统状态</div>\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\" title=\"批量操作\">☑️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div id=\"batchActions\" style=\"display:none;padding:8px;background:var(--bg3);gap:8px;align-items:center\">\n<span style=\"font-size:12px\">已选 <span id=\"selectedCount\">0</span> 个</span>\n<button class=\"btn btn-danger btn-sm\" onclick=\"batchDeleteChats()\">删除</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"batchExportChats()\">导出</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleBatchMode()\">取消</button>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateImage()\" title=\"生成图片\">🎨</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateMindmap()\" title=\"生成思维导图\">🧠</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"saveAsTemplate()\" title=\"保存为模板\">💾</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">双因素认证 (2FA)<br><small style=\"color:var(--text2)\">使用 Google Authenticator 等应用增强账户安全</small></div><div style=\"display:flex;gap:8px\"><span id=\"2faStatus\" style=\"color:var(--text2)\">未启用</span><button class=\"btn btn-ghost btn-sm\" onclick=\"setup2FA()\" id=\"2faBtn\">设置</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录设备管理</div><button class=\"btn btn-ghost btn-sm\" onclick=\"alert('功能开发中')\">查看设备</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">修改密码</div><button class=\"btn btn-ghost btn-sm\" onclick=\"showChangePasswordModal()\">修改</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Agent 工作流页 -->\n<div id=\"page-workflows\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🤖</span> Agent 工作流</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建多步骤自动化任务,让 AI 按流程完成复杂工作</p>\n<div id=\"workflowTemplates\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px\"></div>\n</div>\n<div class=\"settings-section\" id=\"workflowRunner\" style=\"display:none\">\n<h4><span>▶️</span> 运行工作流</h4>\n<div id=\"workflowInputs\"></div>\n<button class=\"btn btn-primary\" onclick=\"executeWorkflow()\">🚀 执行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('workflowRunner').style.display='none'\">取消</button>\n</div>\n<div class=\"settings-section\" id=\"workflowResults\" style=\"display:none\">\n<h4><span>📋</span> 执行结果</h4>\n<div id=\"workflowResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 代码运行器页 -->\n<div id=\"page-code-runner\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>▶️</span> 代码运行器</h4>\n<p style=\"color:var(--text2);margin-bottom:16px\">在线运行 Python / JavaScript 代码</p>\n<div class=\"form-group\">\n<label>语言</label>\n<select id=\"codeLanguage\" style=\"width:150px\">\n<option value=\"python\">Python</option>\n<option value=\"javascript\">JavaScript</option>\n</select>\n</div>\n<div class=\"form-group\">\n<label>代码</label>\n<textarea id=\"codeInput\" rows=\"12\" style=\"font-family:monospace;font-size:13px\" placeholder=\"# 输入代码...\nprint('Hello, World!')\"></textarea>\n</div>\n<div style=\"display:flex;gap:12px\">\n<button class=\"btn btn-primary\" onclick=\"runCode()\">▶️ 运行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('codeInput').value=''\">清空</button>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 输出结果</h4>\n<pre id=\"codeOutput\" style=\"background:var(--bg);padding:16px;border-radius:8px;min-height:100px;font-family:monospace;font-size:13px;white-space:pre-wrap\">等待运行...</pre>\n</div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><div class=\"form-group\" id=\"auth2FAGroup\" style=\"display:none\"><label>2FA 验证码</label><input type=\"text\" id=\"auth2FACode\" placeholder=\"6位验证码\" maxlength=\"6\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><div style=\"display:flex;align-items:center;margin:16px 0\"><div style=\"flex:1;height:1px;background:var(--border)\"></div><span style=\"padding:0 12px;color:var(--text2);font-size:12px\">或</span><div style=\"flex:1;height:1px;background:var(--border)\"></div></div><button class=\"btn btn-ghost\" style=\"width:100%;display:flex;align-items:center;justify-content:center;gap:8px\" onclick=\"loginWithGithub()\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg> 使用 GitHub 登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();if(n.dataset.page==='workflows')loadWorkflowTemplates();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Agent 工作流\nvar workflowTemplates=[];\nvar currentWorkflow=null;\nfunction loadWorkflowTemplates(){api('/api/workflows/templates').then(function(data){workflowTemplates=data;renderWorkflowTemplates()}).catch(function(e){console.error('加载工作流失败:',e)})}\nfunction renderWorkflowTemplates(){var html=workflowTemplates.map(function(w){return'<div style=\"background:var(--bg);border-radius:12px;padding:20px;cursor:pointer\" onclick=\"selectWorkflow(\\''+w.id+'\\')\"><div style=\"display:flex;align-items:center;gap:12px;margin-bottom:12px\"><span style=\"font-size:24px\">🤖</span><div><strong>'+w.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+w.steps.length+' 个步骤</div></div></div><p style=\"font-size:13px;color:var(--text2);line-height:1.5\">'+w.description+'</p></div>'}).join('');$('workflowTemplates').innerHTML=html||'<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无工作流模板</div>'}\nfunction selectWorkflow(id){currentWorkflow=workflowTemplates.find(function(w){return w.id===id});if(!currentWorkflow)return;var inputs=[];currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')&&inputs.indexOf(key)===-1)inputs.push(key)})}});var html=inputs.map(function(key){return'<div class=\"form-group\"><label>'+key+'</label><textarea id=\"wf_'+key+'\" rows=\"3\" placeholder=\"输入 '+key+'\"></textarea></div>'}).join('');$('workflowInputs').innerHTML='<h5 style=\"margin-bottom:16px\">'+currentWorkflow.name+'</h5>'+html;$('workflowRunner').style.display='block';$('workflowResults').style.display='none'}\nfunction executeWorkflow(){if(!currentWorkflow){alert('请先选择工作流');return}var inputData={};currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')){var el=$('wf_'+key);if(el)inputData[key]=el.value}})}});$('workflowResultsContent').innerHTML='<div style=\"text-align:center;padding:40px\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px;color:var(--text2)\">正在执行工作流...</p></div>';$('workflowResults').style.display='block';api('/api/workflows/run',{method:'POST',body:JSON.stringify({name:currentWorkflow.name,steps:currentWorkflow.steps,input_data:inputData})}).then(function(data){var html='';for(var key in data.results){html+='<div style=\"background:var(--bg);border-radius:10px;padding:16px;margin-bottom:12px\"><div style=\"font-weight:600;margin-bottom:8px;color:var(--accent)\">'+key+'</div><div style=\"font-size:14px;line-height:1.6;white-space:pre-wrap\">'+data.results[key]+'</div></div>'}$('workflowResultsContent').innerHTML=html}).catch(function(e){$('workflowResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">执行失败: '+e.message+'</div>'})}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// GitHub 登录\nfunction loginWithGithub(){window.location.href='/api/auth/github'}\n// 2FA 设置\nfunction setup2FA(){if(!authToken){alert('请先登录');return}api('/api/auth/2fa/setup',{method:'POST'}).then(function(data){var html='<div style=\"text-align:center\"><img src=\"'+data.qr_code+'\" style=\"width:200px;height:200px;border-radius:8px\"><p style=\"margin:16px 0;color:var(--text2);font-size:13px\">使用 Google Authenticator 扫描二维码</p><div class=\"form-group\"><label>输入6位验证码确认</label><input type=\"text\" id=\"verify2FACode\" placeholder=\"000000\" maxlength=\"6\" style=\"text-align:center;font-size:20px;letter-spacing:8px\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"verify2FA()\">确认启用</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'2faModal\\')\">取消</button></div></div>';showCustomModal('设置双因素认证',html,'2faModal')}).catch(function(e){alert('设置失败: '+e.message)})}\nfunction verify2FA(){var code=$('verify2FACode').value.trim();if(code.length!==6){alert('请输入6位验证码');return}api('/api/auth/2fa/verify',{method:'POST',body:JSON.stringify({code:code})}).then(function(data){closeModal('2faModal');$('2faStatus').textContent='已启用';$('2faStatus').style.color='var(--success)';$('2faBtn').textContent='禁用';$('2faBtn').onclick=disable2FA;showToast('2FA 已启用')}).catch(function(e){alert('验证失败: '+e.message)})}\nfunction disable2FA(){var code=prompt('输入6位验证码以禁用 2FA:');if(!code)return;api('/api/auth/2fa/disable',{method:'POST',body:JSON.stringify({code:code})}).then(function(){$('2faStatus').textContent='未启用';$('2faStatus').style.color='var(--text2)';$('2faBtn').textContent='设置';$('2faBtn').onclick=setup2FA;showToast('2FA 已禁用')}).catch(function(e){alert('禁用失败: '+e.message)})}\nfunction showChangePasswordModal(){var html='<div class=\"form-group\"><label>当前密码</label><input type=\"password\" id=\"oldPassword\"></div><div class=\"form-group\"><label>新密码</label><input type=\"password\" id=\"newPassword\"></div><div class=\"form-group\"><label>确认新密码</label><input type=\"password\" id=\"confirmPassword\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"changePassword()\">修改</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pwdModal\\')\">取消</button></div>';showCustomModal('修改密码',html,'pwdModal')}\nfunction changePassword(){var oldPwd=$('oldPassword').value,newPwd=$('newPassword').value,confirmPwd=$('confirmPassword').value;if(!oldPwd||!newPwd){alert('请填写密码');return}if(newPwd!==confirmPwd){alert('两次密码不一致');return}alert('密码修改功能开发中')}\n// 检查 URL 中的 token(OAuth 回调)\n(function(){var params=new URLSearchParams(window.location.search);var token=params.get('token');if(token){localStorage.setItem('token',token);authToken=token;window.history.replaceState({},document.title,'/');checkAuth()}})();\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\n// 代码运行器\nfunction runCode(){var code=$('codeInput').value;var lang=$('codeLanguage').value;if(!code.trim()){alert('请输入代码');return}$('codeOutput').textContent='运行中...';$('codeOutput').style.color='var(--text2)';api('/api/code/run',{method:'POST',body:JSON.stringify({code:code,language:lang,timeout:5})}).then(function(data){if(data.success){$('codeOutput').textContent=data.output||'(无输出)';$('codeOutput').style.color='var(--success)'}else{$('codeOutput').textContent='错误: '+(data.error||'未知错误')+'\\n'+data.output;$('codeOutput').style.color='var(--error)'}}).catch(function(e){$('codeOutput').textContent='请求失败: '+e.message;$('codeOutput').style.color='var(--error)'})}\n// 思维导图\nfunction generateMindmap(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}showToast('正在生成思维导图...');api('/api/mindmap/generate',{method:'POST',body:JSON.stringify({messages:chat.messages,title:chat.title})}).then(function(data){renderMindmap(data.nodes)}).catch(function(e){alert('生成失败: '+e.message)})}\nfunction renderMindmap(nodes){var html='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.8);z-index:2000;display:flex;align-items:center;justify-content:center\" onclick=\"if(event.target===this)this.remove()\"><div style=\"background:var(--bg2);border-radius:16px;padding:24px;max-width:800px;max-height:80vh;overflow:auto\"><h3 style=\"margin-bottom:16px\">🧠 思维导图</h3><div id=\"mindmapContent\" style=\"padding:20px\"></div><button class=\"btn btn-ghost\" onclick=\"this.parentElement.parentElement.remove()\">关闭</button></div></div>';document.body.insertAdjacentHTML('beforeend',html);var content='';function renderNode(node,level){var indent=level*24;content+='<div style=\"margin-left:'+indent+'px;padding:8px 12px;margin-bottom:4px;background:var(--bg'+(level>0?'3':'')+');border-radius:6px;border-left:3px solid var(--accent)\">'+(level>0?'├─ ':'')+node.label+'</div>';if(node.children){node.children.forEach(function(c){renderNode(c,level+1)})}}if(nodes&&nodes.length)renderNode(nodes[0],0);$('mindmapContent').innerHTML=content||'<p style=\"color:var(--text2)\">无法生成思维导图</p>'}\n// 保存对话为模板\nfunction saveAsTemplate(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages.length){alert('当前对话为空');return}var name=prompt('模板名称:',chat.title);if(!name)return;api('/api/chat-templates',{method:'POST',body:JSON.stringify({name:name,messages:chat.messages})}).then(function(){showToast('已保存为模板')}).catch(function(e){alert('保存失败: '+e.message)})}\n// 用量配额\nfunction loadQuota(){api('/api/quota').then(function(data){var html='<div style=\"margin-bottom:16px\"><div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Token 使用量</span><span>'+formatNumber(data.tokens_used)+' / '+formatNumber(data.tokens_limit)+'</span></div><div style=\"background:var(--bg3);border-radius:4px;height:8px;overflow:hidden\"><div style=\"background:var(--accent);height:100%;width:'+data.usage_percent+'%\"></div></div></div><p style=\"font-size:12px;color:var(--text2)\">当前套餐: '+data.plan+'</p>';if($('quotaInfo'))$('quotaInfo').innerHTML=html}).catch(function(e){console.error(e)})}\n// PWA 注册\nif('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js').then(function(reg){console.log('SW registered');if('Notification' in window&&Notification.permission==='default'){Notification.requestPermission()}}).catch(function(e){console.error('SW failed:',e)})}\n// 图片生成\nfunction generateImage(){var prompt=prompt('输入图片描述:');if(!prompt)return;showToast('正在生成图片...');api('/api/images/generate',{method:'POST',body:JSON.stringify({prompt:prompt})}).then(function(data){var img='<img src=\"'+data.url+'\" style=\"max-width:100%;border-radius:8px\">';var chat=chats.find(function(c){return c.id===currentChatId});if(chat){chat.messages.push({role:'assistant',content:'![生成的图片]('+data.url+')\\n\\n'+data.revised_prompt});saveChats();renderMessages()}showToast('图片已生成')}).catch(function(e){alert('生成失败: '+e.message)})}\n// TTS 语音合成\nfunction speakText(text){api('/api/audio/tts',{method:'POST',body:JSON.stringify({text:text,voice:'alloy'})}).then(function(data){var audio=new Audio(data.audio);audio.play();showToast('正在播放')}).catch(function(e){if('speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(text);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('TTS 失败: '+e.message)}})}\n// 内容过滤\nfunction filterContent(text){return api('/api/content/filter',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data})}\n// 数据脱敏\nfunction maskData(text){return api('/api/data/mask',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data.masked})}\n// 备份\nfunction createBackup(){api('/api/backup',{method:'POST'}).then(function(data){showToast('备份已创建: '+data.path)}).catch(function(e){alert('备份失败: '+e.message)})}\n// 离线检测\nwindow.addEventListener('online',function(){showToast('网络已恢复')});\nwindow.addEventListener('offline',function(){showToast('网络已断开,部分功能不可用')});\n\n// ========== 性能监控面板 ==========\nfunction showHealthDashboard(){\napi('/api/health/detailed').then(function(data){\nvar html='<div style=\"display:grid;grid-template-columns:repeat(2,1fr);gap:16px\">';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">CPU 使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.cpu_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.cpu_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">内存使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.memory_percent>80?'var(--error)':'var(--success)')+'\">'+data.system.memory_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">磁盘使用率</div><div style=\"font-size:24px;font-weight:600;color:'+(data.system.disk_percent>90?'var(--error)':'var(--success)')+'\">'+data.system.disk_percent+'%</div></div>';\nhtml+='<div style=\"background:var(--bg);padding:16px;border-radius:10px\"><div style=\"font-size:12px;color:var(--text2)\">数据库延迟</div><div style=\"font-size:24px;font-weight:600;color:'+(data.components.database.latency_ms>100?'var(--warning)':'var(--success)')+'\">'+data.components.database.latency_ms+'ms</div></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;padding:16px;background:var(--bg);border-radius:10px\">';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>缓存</span><span>'+data.components.cache.size+'/'+data.components.cache.max_size+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between;margin-bottom:8px\"><span>Redis</span><span style=\"color:'+(data.components.redis.status==='healthy'?'var(--success)':'var(--warning)')+'\">'+data.components.redis.status+'</span></div>';\nhtml+='<div style=\"display:flex;justify-content:space-between\"><span>待处理任务</span><span>'+data.components.task_queue.pending_tasks+'</span></div>';\nhtml+='</div>';\nhtml+='<div style=\"margin-top:16px;text-align:center;font-size:12px;color:var(--text2)\">版本 '+data.version+' · 运行时间 '+formatUptime(data.uptime_seconds)+'</div>';\nshowCustomModal('🖥️ 系统状态',html,'healthModal')\n}).catch(function(e){alert('获取状态失败: '+e.message)})}\nfunction formatUptime(seconds){var h=Math.floor(seconds/3600);var m=Math.floor((seconds%3600)/60);return h+'小时'+m+'分钟'}\n\n// ========== 批量操作 ==========\nvar batchMode=false;\nvar selectedChats=[];\nfunction toggleBatchMode(){batchMode=!batchMode;selectedChats=[];if(batchMode){$('batchActions').style.display='flex';showToast('已进入批量选择模式')}else{$('batchActions').style.display='none'}renderChatList()}\nfunction toggleChatSelection(id,e){if(!batchMode)return;e.stopPropagation();var idx=selectedChats.indexOf(id);if(idx>=0){selectedChats.splice(idx,1)}else{selectedChats.push(id)}renderChatList();$('selectedCount').textContent=selectedChats.length}\nfunction batchDeleteChats(){if(selectedChats.length===0){alert('请先选择对话');return}if(!confirm('确定删除 '+selectedChats.length+' 个对话?'))return;api('/api/conversations/batch-delete',{method:'POST',body:JSON.stringify({ids:selectedChats})}).then(function(data){showToast('已删除 '+data.deleted+' 个对话');selectedChats=[];batchMode=false;$('batchActions').style.display='none';loadChats()}).catch(function(e){alert('删除失败: '+e.message)})}\nfunction batchExportChats(){if(selectedChats.length===0){alert('请先选择对话');return}api('/api/messages/batch-export',{method:'POST',body:JSON.stringify({conversation_ids:selectedChats,format:'json'})}).then(function(data){var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='conversations_export.json';a.click();showToast('已导出 '+data.count+' 个对话')}).catch(function(e){alert('导出失败: '+e.message)})}\n\n// ========== 数据库优化 ==========\nfunction optimizeDatabase(){if(!confirm('确定要优化数据库?这将清理过期数据。'))return;showToast('正在优化...');api('/api/admin/optimize-db',{method:'POST'}).then(function(data){showToast(data.message)}).catch(function(e){alert('优化失败: '+e.message)})}\n\n// ========== 快捷键增强 ==========\ndocument.addEventListener('keydown',function(e){\nif(e.ctrlKey&&e.key==='h'){e.preventDefault();showHealthDashboard()}\nif(e.ctrlKey&&e.key==='b'){e.preventDefault();toggleBatchMode()}\nif(e.ctrlKey&&e.shiftKey&&e.key==='E'){e.preventDefault();batchExportChats()}\n});\n\n// ========== 性能优化:虚拟滚动 ==========\nfunction renderChatListVirtual(){\nvar container=$('chatList');\nvar itemHeight=60;\nvar visibleCount=Math.ceil(container.clientHeight/itemHeight)+2;\nvar scrollTop=container.scrollTop;\nvar startIndex=Math.floor(scrollTop/itemHeight);\nvar endIndex=Math.min(startIndex+visibleCount,chats.length);\nvar html='<div style=\"height:'+(startIndex*itemHeight)+'px\"></div>';\nfor(var i=startIndex;i<endIndex;i++){\nvar c=chats[i];\nvar active=c.id===currentChatId?'active':'';\nvar selected=selectedChats.includes(c.id)?'border:2px solid var(--accent);':'';\nvar checkbox=batchMode?'<input type=\"checkbox\" '+(selectedChats.includes(c.id)?'checked':'')+' onclick=\"toggleChatSelection(\\''+c.id+'\\',event)\" style=\"margin-right:8px\">':'';\nhtml+='<div class=\"sidebar-item '+active+'\" style=\"'+selected+'\" onclick=\"loadChat(\\''+c.id+'\\')\">'+checkbox+'<div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+c.title+'</div><div class=\"sidebar-item-desc\">'+(c.messages.length||0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" style=\"opacity:0\" onclick=\"deleteChat(\\''+c.id+'\\',event)\">🗑️</button></div>'\n}\nhtml+='<div style=\"height:'+((chats.length-endIndex)*itemHeight)+'px\"></div>';\ncontainer.innerHTML=html}\n\n// ========== 请求重试机制 ==========\nasync function apiWithRetry(url,options,maxRetries=3){\nfor(var i=0;i<maxRetries;i++){\ntry{return await api(url,options)}\ncatch(e){\nif(i===maxRetries-1)throw e;\nawait new Promise(function(r){setTimeout(r,1000*(i+1))});\nconsole.log('Retrying request...',i+1)\n}}}\n\n// ========== 消息队列(离线支持) ==========\nvar offlineQueue=JSON.parse(localStorage.getItem('offlineQueue')||'[]');\nfunction queueOfflineMessage(msg){offlineQueue.push({msg:msg,time:Date.now()});localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))}\nfunction processOfflineQueue(){if(offlineQueue.length===0)return;showToast('正在发送离线消息...');var msg=offlineQueue.shift();localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue));sendMessageInternal(msg.msg).then(function(){processOfflineQueue()}).catch(function(){offlineQueue.unshift(msg);localStorage.setItem('offlineQueue',JSON.stringify(offlineQueue))})}\nwindow.addEventListener('online',processOfflineQueue);\n\n// ========== 智能预加载 ==========\nfunction preloadNextChat(){\nvar currentIdx=chats.findIndex(function(c){return c.id===currentChatId});\nif(currentIdx>=0&&currentIdx<chats.length-1){\nvar nextChat=chats[currentIdx+1];\nif(!nextChat.messages||nextChat.messages.length===0){\napi('/api/conversations/'+nextChat.id+'/messages').then(function(msgs){nextChat.messages=msgs})}}}\n\n// ========== 自动保存草稿 ==========\nvar draftTimer=null;\nfunction saveDraft(){var input=$('chatInput').value;if(input&&currentChatId){localStorage.setItem('draft_'+currentChatId,input)}}\nfunction loadDraft(){if(currentChatId){var draft=localStorage.getItem('draft_'+currentChatId);if(draft)$('chatInput').value=draft}}\nfunction clearDraft(){if(currentChatId)localStorage.removeItem('draft_'+currentChatId)}\n$('chatInput').addEventListener('input',function(){clearTimeout(draftTimer);draftTimer=setTimeout(saveDraft,1000)});\n\n// ========== 消息搜索增强 ==========\nfunction searchInCurrentChat(){var q=prompt('在当前对话中搜索:');if(!q)return;var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages)return;var results=chat.messages.filter(function(m){return m.content&&m.content.toLowerCase().includes(q.toLowerCase())});if(results.length===0){alert('未找到匹配消息');return}var html='<div style=\"max-height:400px;overflow-y:auto\">';results.forEach(function(m,i){html+='<div style=\"padding:12px;background:var(--bg);border-radius:8px;margin-bottom:8px\"><div style=\"font-size:12px;color:var(--text2);margin-bottom:4px\">'+(m.role==='user'?'👤 用户':'🤖 助手')+'</div><div style=\"font-size:14px\">'+m.content.slice(0,200)+(m.content.length>200?'...':'')+'</div></div>'});html+='</div>';showCustomModal('搜索结果 ('+results.length+')',html,'searchResultModal')}\n\nconsole.log('🤖 AI Hub v2.0.0 - Enhanced');\n</script>\n</body>\n</html>\n"}, "125cc7680e2eef683597befd78b829761b090050": {"t": 1785765475.1921284, "n": 185227, "h": "939325670266f06c", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"theme-color\" content=\"#0f0f1a\">\n<meta name=\"description\" content=\"AI Hub - 统一 AI 平台\">\n<link rel=\"manifest\" href=\"/static/manifest.json\">\n<link rel=\"apple-touch-icon\" href=\"/static/icon-192.png\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"workflows\"><span class=\"nav-item-icon\">🤖</span> Agent 工作流</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"generateImage()\" title=\"生成图片\">🎨</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">双因素认证 (2FA)<br><small style=\"color:var(--text2)\">使用 Google Authenticator 等应用增强账户安全</small></div><div style=\"display:flex;gap:8px\"><span id=\"2faStatus\" style=\"color:var(--text2)\">未启用</span><button class=\"btn btn-ghost btn-sm\" onclick=\"setup2FA()\" id=\"2faBtn\">设置</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录设备管理</div><button class=\"btn btn-ghost btn-sm\" onclick=\"alert('功能开发中')\">查看设备</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">修改密码</div><button class=\"btn btn-ghost btn-sm\" onclick=\"showChangePasswordModal()\">修改</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Agent 工作流页 -->\n<div id=\"page-workflows\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🤖</span> Agent 工作流</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建多步骤自动化任务,让 AI 按流程完成复杂工作</p>\n<div id=\"workflowTemplates\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px\"></div>\n</div>\n<div class=\"settings-section\" id=\"workflowRunner\" style=\"display:none\">\n<h4><span>▶️</span> 运行工作流</h4>\n<div id=\"workflowInputs\"></div>\n<button class=\"btn btn-primary\" onclick=\"executeWorkflow()\">🚀 执行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('workflowRunner').style.display='none'\">取消</button>\n</div>\n<div class=\"settings-section\" id=\"workflowResults\" style=\"display:none\">\n<h4><span>📋</span> 执行结果</h4>\n<div id=\"workflowResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><div class=\"form-group\" id=\"auth2FAGroup\" style=\"display:none\"><label>2FA 验证码</label><input type=\"text\" id=\"auth2FACode\" placeholder=\"6位验证码\" maxlength=\"6\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><div style=\"display:flex;align-items:center;margin:16px 0\"><div style=\"flex:1;height:1px;background:var(--border)\"></div><span style=\"padding:0 12px;color:var(--text2);font-size:12px\">或</span><div style=\"flex:1;height:1px;background:var(--border)\"></div></div><button class=\"btn btn-ghost\" style=\"width:100%;display:flex;align-items:center;justify-content:center;gap:8px\" onclick=\"loginWithGithub()\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg> 使用 GitHub 登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();if(n.dataset.page==='workflows')loadWorkflowTemplates();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Agent 工作流\nvar workflowTemplates=[];\nvar currentWorkflow=null;\nfunction loadWorkflowTemplates(){api('/api/workflows/templates').then(function(data){workflowTemplates=data;renderWorkflowTemplates()}).catch(function(e){console.error('加载工作流失败:',e)})}\nfunction renderWorkflowTemplates(){var html=workflowTemplates.map(function(w){return'<div style=\"background:var(--bg);border-radius:12px;padding:20px;cursor:pointer\" onclick=\"selectWorkflow(\\''+w.id+'\\')\"><div style=\"display:flex;align-items:center;gap:12px;margin-bottom:12px\"><span style=\"font-size:24px\">🤖</span><div><strong>'+w.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+w.steps.length+' 个步骤</div></div></div><p style=\"font-size:13px;color:var(--text2);line-height:1.5\">'+w.description+'</p></div>'}).join('');$('workflowTemplates').innerHTML=html||'<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无工作流模板</div>'}\nfunction selectWorkflow(id){currentWorkflow=workflowTemplates.find(function(w){return w.id===id});if(!currentWorkflow)return;var inputs=[];currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')&&inputs.indexOf(key)===-1)inputs.push(key)})}});var html=inputs.map(function(key){return'<div class=\"form-group\"><label>'+key+'</label><textarea id=\"wf_'+key+'\" rows=\"3\" placeholder=\"输入 '+key+'\"></textarea></div>'}).join('');$('workflowInputs').innerHTML='<h5 style=\"margin-bottom:16px\">'+currentWorkflow.name+'</h5>'+html;$('workflowRunner').style.display='block';$('workflowResults').style.display='none'}\nfunction executeWorkflow(){if(!currentWorkflow){alert('请先选择工作流');return}var inputData={};currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')){var el=$('wf_'+key);if(el)inputData[key]=el.value}})}});$('workflowResultsContent').innerHTML='<div style=\"text-align:center;padding:40px\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px;color:var(--text2)\">正在执行工作流...</p></div>';$('workflowResults').style.display='block';api('/api/workflows/run',{method:'POST',body:JSON.stringify({name:currentWorkflow.name,steps:currentWorkflow.steps,input_data:inputData})}).then(function(data){var html='';for(var key in data.results){html+='<div style=\"background:var(--bg);border-radius:10px;padding:16px;margin-bottom:12px\"><div style=\"font-weight:600;margin-bottom:8px;color:var(--accent)\">'+key+'</div><div style=\"font-size:14px;line-height:1.6;white-space:pre-wrap\">'+data.results[key]+'</div></div>'}$('workflowResultsContent').innerHTML=html}).catch(function(e){$('workflowResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">执行失败: '+e.message+'</div>'})}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// GitHub 登录\nfunction loginWithGithub(){window.location.href='/api/auth/github'}\n// 2FA 设置\nfunction setup2FA(){if(!authToken){alert('请先登录');return}api('/api/auth/2fa/setup',{method:'POST'}).then(function(data){var html='<div style=\"text-align:center\"><img src=\"'+data.qr_code+'\" style=\"width:200px;height:200px;border-radius:8px\"><p style=\"margin:16px 0;color:var(--text2);font-size:13px\">使用 Google Authenticator 扫描二维码</p><div class=\"form-group\"><label>输入6位验证码确认</label><input type=\"text\" id=\"verify2FACode\" placeholder=\"000000\" maxlength=\"6\" style=\"text-align:center;font-size:20px;letter-spacing:8px\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"verify2FA()\">确认启用</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'2faModal\\')\">取消</button></div></div>';showCustomModal('设置双因素认证',html,'2faModal')}).catch(function(e){alert('设置失败: '+e.message)})}\nfunction verify2FA(){var code=$('verify2FACode').value.trim();if(code.length!==6){alert('请输入6位验证码');return}api('/api/auth/2fa/verify',{method:'POST',body:JSON.stringify({code:code})}).then(function(data){closeModal('2faModal');$('2faStatus').textContent='已启用';$('2faStatus').style.color='var(--success)';$('2faBtn').textContent='禁用';$('2faBtn').onclick=disable2FA;showToast('2FA 已启用')}).catch(function(e){alert('验证失败: '+e.message)})}\nfunction disable2FA(){var code=prompt('输入6位验证码以禁用 2FA:');if(!code)return;api('/api/auth/2fa/disable',{method:'POST',body:JSON.stringify({code:code})}).then(function(){$('2faStatus').textContent='未启用';$('2faStatus').style.color='var(--text2)';$('2faBtn').textContent='设置';$('2faBtn').onclick=setup2FA;showToast('2FA 已禁用')}).catch(function(e){alert('禁用失败: '+e.message)})}\nfunction showChangePasswordModal(){var html='<div class=\"form-group\"><label>当前密码</label><input type=\"password\" id=\"oldPassword\"></div><div class=\"form-group\"><label>新密码</label><input type=\"password\" id=\"newPassword\"></div><div class=\"form-group\"><label>确认新密码</label><input type=\"password\" id=\"confirmPassword\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"changePassword()\">修改</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pwdModal\\')\">取消</button></div>';showCustomModal('修改密码',html,'pwdModal')}\nfunction changePassword(){var oldPwd=$('oldPassword').value,newPwd=$('newPassword').value,confirmPwd=$('confirmPassword').value;if(!oldPwd||!newPwd){alert('请填写密码');return}if(newPwd!==confirmPwd){alert('两次密码不一致');return}alert('密码修改功能开发中')}\n// 检查 URL 中的 token(OAuth 回调)\n(function(){var params=new URLSearchParams(window.location.search);var token=params.get('token');if(token){localStorage.setItem('token',token);authToken=token;window.history.replaceState({},document.title,'/');checkAuth()}})();\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\n// PWA 注册\nif('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js').then(function(reg){console.log('SW registered');if('Notification' in window&&Notification.permission==='default'){Notification.requestPermission()}}).catch(function(e){console.error('SW failed:',e)})}\n// 图片生成\nfunction generateImage(){var prompt=prompt('输入图片描述:');if(!prompt)return;showToast('正在生成图片...');api('/api/images/generate',{method:'POST',body:JSON.stringify({prompt:prompt})}).then(function(data){var img='<img src=\"'+data.url+'\" style=\"max-width:100%;border-radius:8px\">';var chat=chats.find(function(c){return c.id===currentChatId});if(chat){chat.messages.push({role:'assistant',content:'![生成的图片]('+data.url+')\\n\\n'+data.revised_prompt});saveChats();renderMessages()}showToast('图片已生成')}).catch(function(e){alert('生成失败: '+e.message)})}\n// TTS 语音合成\nfunction speakText(text){api('/api/audio/tts',{method:'POST',body:JSON.stringify({text:text,voice:'alloy'})}).then(function(data){var audio=new Audio(data.audio);audio.play();showToast('正在播放')}).catch(function(e){if('speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(text);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('TTS 失败: '+e.message)}})}\n// 内容过滤\nfunction filterContent(text){return api('/api/content/filter',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data})}\n// 数据脱敏\nfunction maskData(text){return api('/api/data/mask',{method:'POST',body:JSON.stringify({text:text})}).then(function(data){return data.masked})}\n// 备份\nfunction createBackup(){api('/api/backup',{method:'POST'}).then(function(data){showToast('备份已创建: '+data.path)}).catch(function(e){alert('备份失败: '+e.message)})}\n// 离线检测\nwindow.addEventListener('online',function(){showToast('网络已恢复')});\nwindow.addEventListener('offline',function(){showToast('网络已断开,部分功能不可用')});\nconsole.log('🤖 AI Hub v2.0.0');\n</script>\n</body>\n</html>\n"}, "9d896fa779da878b772c415aedd94642275f3628": {"t": 1785765476.926698, "n": 183075, "h": "2a99c2c966406755", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"workflows\"><span class=\"nav-item-icon\">🤖</span> Agent 工作流</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">双因素认证 (2FA)<br><small style=\"color:var(--text2)\">使用 Google Authenticator 等应用增强账户安全</small></div><div style=\"display:flex;gap:8px\"><span id=\"2faStatus\" style=\"color:var(--text2)\">未启用</span><button class=\"btn btn-ghost btn-sm\" onclick=\"setup2FA()\" id=\"2faBtn\">设置</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录设备管理</div><button class=\"btn btn-ghost btn-sm\" onclick=\"alert('功能开发中')\">查看设备</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">修改密码</div><button class=\"btn btn-ghost btn-sm\" onclick=\"showChangePasswordModal()\">修改</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Agent 工作流页 -->\n<div id=\"page-workflows\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🤖</span> Agent 工作流</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建多步骤自动化任务,让 AI 按流程完成复杂工作</p>\n<div id=\"workflowTemplates\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px\"></div>\n</div>\n<div class=\"settings-section\" id=\"workflowRunner\" style=\"display:none\">\n<h4><span>▶️</span> 运行工作流</h4>\n<div id=\"workflowInputs\"></div>\n<button class=\"btn btn-primary\" onclick=\"executeWorkflow()\">🚀 执行</button>\n<button class=\"btn btn-ghost\" onclick=\"$('workflowRunner').style.display='none'\">取消</button>\n</div>\n<div class=\"settings-section\" id=\"workflowResults\" style=\"display:none\">\n<h4><span>📋</span> 执行结果</h4>\n<div id=\"workflowResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><div class=\"form-group\" id=\"auth2FAGroup\" style=\"display:none\"><label>2FA 验证码</label><input type=\"text\" id=\"auth2FACode\" placeholder=\"6位验证码\" maxlength=\"6\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><div style=\"display:flex;align-items:center;margin:16px 0\"><div style=\"flex:1;height:1px;background:var(--border)\"></div><span style=\"padding:0 12px;color:var(--text2);font-size:12px\">或</span><div style=\"flex:1;height:1px;background:var(--border)\"></div></div><button class=\"btn btn-ghost\" style=\"width:100%;display:flex;align-items:center;justify-content:center;gap:8px\" onclick=\"loginWithGithub()\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg> 使用 GitHub 登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();if(n.dataset.page==='workflows')loadWorkflowTemplates();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Agent 工作流\nvar workflowTemplates=[];\nvar currentWorkflow=null;\nfunction loadWorkflowTemplates(){api('/api/workflows/templates').then(function(data){workflowTemplates=data;renderWorkflowTemplates()}).catch(function(e){console.error('加载工作流失败:',e)})}\nfunction renderWorkflowTemplates(){var html=workflowTemplates.map(function(w){return'<div style=\"background:var(--bg);border-radius:12px;padding:20px;cursor:pointer\" onclick=\"selectWorkflow(\\''+w.id+'\\')\"><div style=\"display:flex;align-items:center;gap:12px;margin-bottom:12px\"><span style=\"font-size:24px\">🤖</span><div><strong>'+w.name+'</strong><div style=\"font-size:12px;color:var(--text2)\">'+w.steps.length+' 个步骤</div></div></div><p style=\"font-size:13px;color:var(--text2);line-height:1.5\">'+w.description+'</p></div>'}).join('');$('workflowTemplates').innerHTML=html||'<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无工作流模板</div>'}\nfunction selectWorkflow(id){currentWorkflow=workflowTemplates.find(function(w){return w.id===id});if(!currentWorkflow)return;var inputs=[];currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')&&inputs.indexOf(key)===-1)inputs.push(key)})}});var html=inputs.map(function(key){return'<div class=\"form-group\"><label>'+key+'</label><textarea id=\"wf_'+key+'\" rows=\"3\" placeholder=\"输入 '+key+'\"></textarea></div>'}).join('');$('workflowInputs').innerHTML='<h5 style=\"margin-bottom:16px\">'+currentWorkflow.name+'</h5>'+html;$('workflowRunner').style.display='block';$('workflowResults').style.display='none'}\nfunction executeWorkflow(){if(!currentWorkflow){alert('请先选择工作流');return}var inputData={};currentWorkflow.steps.forEach(function(s){var matches=s.prompt.match(/\\{(\\w+)\\}/g);if(matches){matches.forEach(function(m){var key=m.slice(1,-1);if(!key.startsWith('result.')){var el=$('wf_'+key);if(el)inputData[key]=el.value}})}});$('workflowResultsContent').innerHTML='<div style=\"text-align:center;padding:40px\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px;color:var(--text2)\">正在执行工作流...</p></div>';$('workflowResults').style.display='block';api('/api/workflows/run',{method:'POST',body:JSON.stringify({name:currentWorkflow.name,steps:currentWorkflow.steps,input_data:inputData})}).then(function(data){var html='';for(var key in data.results){html+='<div style=\"background:var(--bg);border-radius:10px;padding:16px;margin-bottom:12px\"><div style=\"font-weight:600;margin-bottom:8px;color:var(--accent)\">'+key+'</div><div style=\"font-size:14px;line-height:1.6;white-space:pre-wrap\">'+data.results[key]+'</div></div>'}$('workflowResultsContent').innerHTML=html}).catch(function(e){$('workflowResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">执行失败: '+e.message+'</div>'})}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// GitHub 登录\nfunction loginWithGithub(){window.location.href='/api/auth/github'}\n// 2FA 设置\nfunction setup2FA(){if(!authToken){alert('请先登录');return}api('/api/auth/2fa/setup',{method:'POST'}).then(function(data){var html='<div style=\"text-align:center\"><img src=\"'+data.qr_code+'\" style=\"width:200px;height:200px;border-radius:8px\"><p style=\"margin:16px 0;color:var(--text2);font-size:13px\">使用 Google Authenticator 扫描二维码</p><div class=\"form-group\"><label>输入6位验证码确认</label><input type=\"text\" id=\"verify2FACode\" placeholder=\"000000\" maxlength=\"6\" style=\"text-align:center;font-size:20px;letter-spacing:8px\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"verify2FA()\">确认启用</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'2faModal\\')\">取消</button></div></div>';showCustomModal('设置双因素认证',html,'2faModal')}).catch(function(e){alert('设置失败: '+e.message)})}\nfunction verify2FA(){var code=$('verify2FACode').value.trim();if(code.length!==6){alert('请输入6位验证码');return}api('/api/auth/2fa/verify',{method:'POST',body:JSON.stringify({code:code})}).then(function(data){closeModal('2faModal');$('2faStatus').textContent='已启用';$('2faStatus').style.color='var(--success)';$('2faBtn').textContent='禁用';$('2faBtn').onclick=disable2FA;showToast('2FA 已启用')}).catch(function(e){alert('验证失败: '+e.message)})}\nfunction disable2FA(){var code=prompt('输入6位验证码以禁用 2FA:');if(!code)return;api('/api/auth/2fa/disable',{method:'POST',body:JSON.stringify({code:code})}).then(function(){$('2faStatus').textContent='未启用';$('2faStatus').style.color='var(--text2)';$('2faBtn').textContent='设置';$('2faBtn').onclick=setup2FA;showToast('2FA 已禁用')}).catch(function(e){alert('禁用失败: '+e.message)})}\nfunction showChangePasswordModal(){var html='<div class=\"form-group\"><label>当前密码</label><input type=\"password\" id=\"oldPassword\"></div><div class=\"form-group\"><label>新密码</label><input type=\"password\" id=\"newPassword\"></div><div class=\"form-group\"><label>确认新密码</label><input type=\"password\" id=\"confirmPassword\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"changePassword()\">修改</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pwdModal\\')\">取消</button></div>';showCustomModal('修改密码',html,'pwdModal')}\nfunction changePassword(){var oldPwd=$('oldPassword').value,newPwd=$('newPassword').value,confirmPwd=$('confirmPassword').value;if(!oldPwd||!newPwd){alert('请填写密码');return}if(newPwd!==confirmPwd){alert('两次密码不一致');return}alert('密码修改功能开发中')}\n// 检查 URL 中的 token(OAuth 回调)\n(function(){var params=new URLSearchParams(window.location.search);var token=params.get('token');if(token){localStorage.setItem('token',token);authToken=token;window.history.replaceState({},document.title,'/');checkAuth()}})();\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\nconsole.log('🤖 AI Hub v1.8.0');\n</script>\n</body>\n</html>\n"}, "4a13d3ac3177ba0f1ee6ebba09931544a7672ac5": {"t": 1785765478.8363223, "n": 179142, "h": "87ab5ae8e6bdc27f", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔐</span> 安全设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">双因素认证 (2FA)<br><small style=\"color:var(--text2)\">使用 Google Authenticator 等应用增强账户安全</small></div><div style=\"display:flex;gap:8px\"><span id=\"2faStatus\" style=\"color:var(--text2)\">未启用</span><button class=\"btn btn-ghost btn-sm\" onclick=\"setup2FA()\" id=\"2faBtn\">设置</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">登录设备管理</div><button class=\"btn btn-ghost btn-sm\" onclick=\"alert('功能开发中')\">查看设备</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">修改密码</div><button class=\"btn btn-ghost btn-sm\" onclick=\"showChangePasswordModal()\">修改</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><div class=\"form-group\" id=\"auth2FAGroup\" style=\"display:none\"><label>2FA 验证码</label><input type=\"text\" id=\"auth2FACode\" placeholder=\"6位验证码\" maxlength=\"6\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><div style=\"display:flex;align-items:center;margin:16px 0\"><div style=\"flex:1;height:1px;background:var(--border)\"></div><span style=\"padding:0 12px;color:var(--text2);font-size:12px\">或</span><div style=\"flex:1;height:1px;background:var(--border)\"></div></div><button class=\"btn btn-ghost\" style=\"width:100%;display:flex;align-items:center;justify-content:center;gap:8px\" onclick=\"loginWithGithub()\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg> 使用 GitHub 登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// GitHub 登录\nfunction loginWithGithub(){window.location.href='/api/auth/github'}\n// 2FA 设置\nfunction setup2FA(){if(!authToken){alert('请先登录');return}api('/api/auth/2fa/setup',{method:'POST'}).then(function(data){var html='<div style=\"text-align:center\"><img src=\"'+data.qr_code+'\" style=\"width:200px;height:200px;border-radius:8px\"><p style=\"margin:16px 0;color:var(--text2);font-size:13px\">使用 Google Authenticator 扫描二维码</p><div class=\"form-group\"><label>输入6位验证码确认</label><input type=\"text\" id=\"verify2FACode\" placeholder=\"000000\" maxlength=\"6\" style=\"text-align:center;font-size:20px;letter-spacing:8px\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"verify2FA()\">确认启用</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'2faModal\\')\">取消</button></div></div>';showCustomModal('设置双因素认证',html,'2faModal')}).catch(function(e){alert('设置失败: '+e.message)})}\nfunction verify2FA(){var code=$('verify2FACode').value.trim();if(code.length!==6){alert('请输入6位验证码');return}api('/api/auth/2fa/verify',{method:'POST',body:JSON.stringify({code:code})}).then(function(data){closeModal('2faModal');$('2faStatus').textContent='已启用';$('2faStatus').style.color='var(--success)';$('2faBtn').textContent='禁用';$('2faBtn').onclick=disable2FA;showToast('2FA 已启用')}).catch(function(e){alert('验证失败: '+e.message)})}\nfunction disable2FA(){var code=prompt('输入6位验证码以禁用 2FA:');if(!code)return;api('/api/auth/2fa/disable',{method:'POST',body:JSON.stringify({code:code})}).then(function(){$('2faStatus').textContent='未启用';$('2faStatus').style.color='var(--text2)';$('2faBtn').textContent='设置';$('2faBtn').onclick=setup2FA;showToast('2FA 已禁用')}).catch(function(e){alert('禁用失败: '+e.message)})}\nfunction showChangePasswordModal(){var html='<div class=\"form-group\"><label>当前密码</label><input type=\"password\" id=\"oldPassword\"></div><div class=\"form-group\"><label>新密码</label><input type=\"password\" id=\"newPassword\"></div><div class=\"form-group\"><label>确认新密码</label><input type=\"password\" id=\"confirmPassword\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"changePassword()\">修改</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'pwdModal\\')\">取消</button></div>';showCustomModal('修改密码',html,'pwdModal')}\nfunction changePassword(){var oldPwd=$('oldPassword').value,newPwd=$('newPassword').value,confirmPwd=$('confirmPassword').value;if(!oldPwd||!newPwd){alert('请填写密码');return}if(newPwd!==confirmPwd){alert('两次密码不一致');return}alert('密码修改功能开发中')}\n// 检查 URL 中的 token(OAuth 回调)\n(function(){var params=new URLSearchParams(window.location.search);var token=params.get('token');if(token){localStorage.setItem('token',token);authToken=token;window.history.replaceState({},document.title,'/');checkAuth()}})();\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\nconsole.log('🤖 AI Hub v1.8.0');\n</script>\n</body>\n</html>\n"}, "69e00890fac6bc6597781bd26b887a3902610fae": {"t": 1785765480.8167787, "n": 174359, "h": "f0a2435775f81833", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 7天使用趋势</h4>\n<div id=\"usageChart\" style=\"background:var(--bg);border-radius:8px;padding:20px;height:200px;display:flex;align-items:flex-end;gap:8px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💰</span> 成本估算</h4>\n<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:16px\">\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--accent)\" id=\"costToday\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--warning)\" id=\"costMonth\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">本月成本</div>\n</div>\n<div style=\"background:var(--bg);padding:16px;border-radius:10px;text-align:center\">\n<div style=\"font-size:24px;font-weight:700;color:var(--success)\" id=\"costTotal\">$0.00</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总成本</div>\n</div>\n</div>\n<p style=\"font-size:11px;color:var(--text2);margin-top:12px\">* 成本按 GPT-4 价格估算:输入 $0.03/1K,输出 $0.06/1K</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>⭐</span> 模型评分统计</h4>\n<div id=\"ratingStats\" style=\"background:var(--bg);border-radius:8px;padding:16px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);var inputCost=(data.tokens_input||0)/1000*0.03;var outputCost=(data.tokens_output||0)/1000*0.06;var totalCost=inputCost+outputCost;$('costTotal').textContent='$'+totalCost.toFixed(2);$('costToday').textContent='$'+(totalCost*0.1).toFixed(2);$('costMonth').textContent='$'+(totalCost*0.7).toFixed(2);if(data.daily_stats&&data.daily_stats.length>0){var maxCalls=Math.max.apply(null,data.daily_stats.map(function(d){return d.calls}));var chartHtml=data.daily_stats.map(function(d){var height=maxCalls>0?(d.calls/maxCalls*150):0;return'<div style=\"flex:1;display:flex;flex-direction:column;align-items:center\"><div style=\"width:100%;background:var(--accent);border-radius:4px 4px 0 0;height:'+height+'px;min-height:4px\"></div><div style=\"font-size:10px;color:var(--text2);margin-top:8px\">'+d.day.slice(5)+'</div><div style=\"font-size:11px;color:var(--text)\">'+d.calls+'</div></div>'}).join('');$('usageChart').innerHTML=chartHtml}if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs();loadRatingStats()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadRatingStats(){api('/api/ratings/stats').then(function(data){if(data.length===0){$('ratingStats').innerHTML='<div style=\"text-align:center;color:var(--text2)\">暂无评分数据</div>';return}var html=data.map(function(r){var stars='⭐'.repeat(Math.round(r.avg_rating));return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)\"><span>'+r.model+'</span><span>'+stars+' ('+r.avg_rating.toFixed(1)+') · '+r.count+'次评分</span></div>'}).join('');$('ratingStats').innerHTML=html}).catch(function(e){console.error(e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\nconsole.log('🤖 AI Hub v1.8.0');\n</script>\n</body>\n</html>\n"}, "485ef4a3d1e78b5dbedb6bc34fc6227664765d4a": {"t": 1785765482.8024268, "n": 171437, "h": "c45b86274c530664", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n<div class=\"nav-item\" data-page=\"tokens\"><span class=\"nav-item-icon\">🔑</span> API Token</div>\n<div class=\"nav-item\" data-page=\"teams\"><span class=\"nav-item-icon\">👥</span> 团队空间</div>\n<div class=\"nav-item\" data-page=\"knowledge\"><span class=\"nav-item-icon\">📚</span> 知识库</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- API Token 页 -->\n<div id=\"page-tokens\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>🔑</span> API Token 管理</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTokenModal()\">+ 创建 Token</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">创建 API Token 用于第三方应用访问</p>\n<div id=\"tokenList\"></div>\n</div>\n</div></div></div></div>\n<!-- 团队空间页 -->\n<div id=\"page-teams\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>👥</span> 团队空间</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateTeamModal()\">+ 创建团队</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">与团队成员共享对话和模板</p>\n<div id=\"teamList\"></div>\n</div>\n</div></div></div></div>\n<!-- 知识库页 -->\n<div id=\"page-knowledge\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 知识库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showCreateKBModal()\">+ 创建知识库</button>\n</div>\n<p style=\"color:var(--text2);margin-bottom:20px\">上传文档建立私有知识库,让 AI 基于你的资料回答</p>\n<div id=\"kbList\"></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats();if(n.dataset.page==='tokens')loadTokens();if(n.dataset.page==='teams')loadTeams();if(n.dataset.page==='knowledge')loadKnowledgeBases();closeMobileMenus()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button><button class=\"message-action-btn\" onclick=\"rateMessage('+i+')\" title=\"评分\">⭐</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button><button class=\"message-action-btn\" onclick=\"branchFromMessage('+i+')\" title=\"从此分支\">🌿</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx,.json,.csv';input.onchange=function(e){var file=e.target.files[0];if(!file)return;if(file.size>10*1024*1024){alert('文件大小不能超过10MB');return}var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.content){$('chatInput').value='请分析以下文档内容:\\n\\n'+data.content.slice(0,8000);showToast('文件已加载: '+data.filename)}else{alert('解析失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\n// 语音输入\nvar isRecording=false;\nvar mediaRecorder=null;\nvar audioChunks=[];\nfunction voiceInput(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert('您的浏览器不支持语音输入');return}if(isRecording){stopRecording();return}navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){isRecording=true;audioChunks=[];mediaRecorder=new MediaRecorder(stream);mediaRecorder.ondataavailable=function(e){audioChunks.push(e.data)};mediaRecorder.onstop=function(){var audioBlob=new Blob(audioChunks,{type:'audio/wav'});stream.getTracks().forEach(function(t){t.stop()});transcribeAudio(audioBlob)};mediaRecorder.start();showToast('🎤 正在录音...点击停止');document.querySelector('[onclick=\"voiceInput()\"]').style.color='var(--error)'}).catch(function(e){alert('无法访问麦克风: '+e.message)})}\nfunction stopRecording(){if(mediaRecorder&&isRecording){isRecording=false;mediaRecorder.stop();document.querySelector('[onclick=\"voiceInput()\"]').style.color=''}}\nfunction transcribeAudio(blob){showToast('正在识别语音...');if('webkitSpeechRecognition' in window||'SpeechRecognition' in window){var SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition;var recognition=new SpeechRecognition();recognition.lang='zh-CN';recognition.continuous=false;recognition.interimResults=false;recognition.onresult=function(e){var text=e.results[0][0].transcript;$('chatInput').value+=text;showToast('语音识别完成')};recognition.onerror=function(e){showToast('识别失败: '+e.error)};recognition.start()}else{showToast('浏览器不支持语音识别,请使用Chrome')}}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction branchFromMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var branchId='chat_'+Date.now();var branchMessages=chat.messages.slice(0,index+1);chats.unshift({id:branchId,title:'分支: '+(chat.title||'对话').slice(0,15),messages:JSON.parse(JSON.stringify(branchMessages)),provider:chat.provider,model:chat.model,assistant:chat.assistant,parentId:currentChatId,branchIndex:index});saveChats();renderChats();selectChat(branchId);showToast('已创建分支对话')}\nfunction rateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var rating=prompt('给这条回复评分 (1-5分):',chat.messages[index].rating||'');if(rating===null)return;var score=parseInt(rating);if(isNaN(score)||score<1||score>5){alert('请输入1-5的数字');return}chat.messages[index].rating=score;saveChats();showToast('已评分: '+score+'⭐');if(authToken){api('/api/ratings',{method:'POST',body:JSON.stringify({conversation_id:currentChatId,message_index:index,rating:score,model:chat.model})}).catch(function(e){console.error('保存评分失败:',e)})}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// API Token 管理\nfunction loadTokens(){api('/api/tokens').then(function(data){if(data.length===0){$('tokenList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无 Token</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px;font-family:monospace\">'+t.token+'</div><div style=\"font-size:11px;color:var(--text2);margin-top:4px\">创建于 '+(t.created_at||'').slice(0,10)+'</div></div><button class=\"btn btn-danger btn-sm\" onclick=\"deleteToken('+t.id+')\">删除</button></div>'}).join('');$('tokenList').innerHTML=html}).catch(function(e){$('tokenList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTokenModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"tokenName\" placeholder=\"我的应用\"></div><div class=\"form-group\"><label>有效期(天)</label><input type=\"number\" id=\"tokenExpires\" value=\"30\" min=\"1\" max=\"365\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createToken()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'tokenModal\\')\">取消</button></div>';showCustomModal('创建 API Token',html,'tokenModal')}\nfunction createToken(){var name=$('tokenName').value.trim()||'API Token';var days=parseInt($('tokenExpires').value)||30;api('/api/tokens',{method:'POST',body:JSON.stringify({name:name,expires_days:days})}).then(function(data){closeModal('tokenModal');prompt('Token 已创建(仅显示一次):',data.token);loadTokens()}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction deleteToken(id){if(!confirm('确定删除?'))return;api('/api/tokens/'+id,{method:'DELETE'}).then(function(){loadTokens();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 团队空间\nfunction loadTeams(){api('/api/teams').then(function(data){if(data.length===0){$('teamList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无团队</div>';return}var html=data.map(function(t){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>'+t.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">角色: '+t.role+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"manageTeam('+t.id+')\">管理</button></div>'}).join('');$('teamList').innerHTML=html}).catch(function(e){$('teamList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateTeamModal(){var html='<div class=\"form-group\"><label>团队名称</label><input type=\"text\" id=\"teamName\" placeholder=\"我的团队\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createTeam()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'teamModal\\')\">取消</button></div>';showCustomModal('创建团队',html,'teamModal')}\nfunction createTeam(){var name=$('teamName').value.trim();if(!name){alert('请输入团队名称');return}api('/api/teams',{method:'POST',body:JSON.stringify({name:name})}).then(function(){closeModal('teamModal');loadTeams();showToast('团队已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction manageTeam(id){alert('团队管理功能开发中')}\n// 知识库\nfunction loadKnowledgeBases(){api('/api/knowledge-bases').then(function(data){if(data.length===0){$('kbList').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\">暂无知识库</div>';return}var html=data.map(function(kb){return'<div style=\"display:flex;justify-content:space-between;align-items:center;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px\"><div><strong>📚 '+kb.name+'</strong><div style=\"font-size:12px;color:var(--text2);margin-top:4px\">'+(kb.description||'无描述')+'</div></div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"uploadToKB('+kb.id+')\">上传文档</button><button class=\"btn btn-ghost btn-sm\" onclick=\"searchKB('+kb.id+')\">搜索</button></div></div>'}).join('');$('kbList').innerHTML=html}).catch(function(e){$('kbList').innerHTML='<div style=\"color:var(--error);padding:20px\">加载失败,请先登录</div>'})}\nfunction showCreateKBModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"kbName\" placeholder=\"我的知识库\"></div><div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"kbDesc\" placeholder=\"可选\"></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"createKB()\">创建</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'kbModal\\')\">取消</button></div>';showCustomModal('创建知识库',html,'kbModal')}\nfunction createKB(){var name=$('kbName').value.trim();if(!name){alert('请输入名称');return}api('/api/knowledge-bases',{method:'POST',body:JSON.stringify({name:name,description:$('kbDesc').value})}).then(function(){closeModal('kbModal');loadKnowledgeBases();showToast('知识库已创建')}).catch(function(e){alert('创建失败: '+e.message)})}\nfunction uploadToKB(kbId){var input=document.createElement('input');input.type='file';input.accept='.txt,.md,.pdf,.doc,.docx';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/knowledge-bases/'+kbId+'/documents',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){if(data.success){showToast('文档已上传: '+data.filename)}else{alert('上传失败')}}).catch(function(e){alert('上传失败: '+e.message)})};input.click()}\nfunction searchKB(kbId){var q=prompt('输入搜索关键词:');if(!q)return;api('/api/knowledge-bases/'+kbId+'/search?q='+encodeURIComponent(q)).then(function(data){if(data.length===0){alert('未找到结果');return}var result=data.map(function(d){return d.filename+': '+d.content.slice(0,200)+'...'}).join('\\n\\n');alert('搜索结果:\\n\\n'+result)}).catch(function(e){alert('搜索失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\nconsole.log('🤖 AI Hub v1.8.0');\n</script>\n</body>\n</html>\n"}, "a190043b553d6538a89d4837bd4c482b63dfd2da": {"t": 1785765484.9652472, "n": 159927, "h": "540347456e22fffd", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"prompts\"><span class=\"nav-item-icon\">📋</span> Prompt 模板</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- Prompt 模板页 -->\n<div id=\"page-prompts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📋</span> Prompt 模板库</h4>\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddPromptModal()\">+ 新建模板</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap\">\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn active\" onclick=\"filterPrompts('all',this)\">全部</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('writing',this)\">✍️ 写作</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('coding',this)\">💻 编程</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('translate',this)\">🌐 翻译</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('analysis',this)\">📊 分析</button>\n<button class=\"btn btn-ghost btn-sm prompt-cat-btn\" onclick=\"filterPrompts('creative',this)\">🎨 创意</button>\n</div>\n<div id=\"promptList\" style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){alert('文件上传功能开发中')}\nfunction voiceInput(){alert('语音输入功能开发中')}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();loadPrompts();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// Prompt 模板\nvar promptTemplates=[];\nvar currentPromptCategory='all';\nfunction loadPrompts(){api('/api/prompts').then(function(data){promptTemplates=data;renderPrompts()}).catch(function(e){console.error('加载模板失败:',e)})}\nfunction renderPrompts(){var filtered=currentPromptCategory==='all'?promptTemplates:promptTemplates.filter(function(p){return p.category===currentPromptCategory});if(filtered.length===0){$('promptList').innerHTML='<div style=\"grid-column:1/-1;text-align:center;padding:40px;color:var(--text2)\"><span style=\"font-size:48px;display:block;margin-bottom:16px\">📋</span><p>暂无模板</p><p style=\"font-size:12px;margin-top:8px\">点击右上角新建模板</p></div>';return}var html=filtered.map(function(p){return'<div style=\"background:var(--bg);border-radius:12px;padding:16px;cursor:pointer\" onclick=\"usePrompt('+p.id+')\" oncontextmenu=\"showPromptMenu(event,'+p.id+')\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\"><strong style=\"font-size:14px\">'+p.name+'</strong><span style=\"font-size:11px;padding:2px 8px;background:var(--bg3);border-radius:4px\">'+getCategoryEmoji(p.category)+'</span></div><div style=\"font-size:13px;color:var(--text2);line-height:1.5;max-height:60px;overflow:hidden\">'+p.content.slice(0,100)+'...</div><div style=\"margin-top:12px;font-size:11px;color:var(--text2)\">使用 '+p.use_count+' 次</div></div>'}).join('');$('promptList').innerHTML=html}\nfunction getCategoryEmoji(cat){var map={writing:'✍️',coding:'💻',translate:'🌐',analysis:'📊',creative:'🎨',general:'📋'};return map[cat]||'📋'}\nfunction filterPrompts(cat,btn){currentPromptCategory=cat;document.querySelectorAll('.prompt-cat-btn').forEach(function(b){b.classList.remove('active')});if(btn)btn.classList.add('active');renderPrompts()}\nfunction usePrompt(id){var p=promptTemplates.find(function(x){return x.id===id});if(!p)return;$('chatInput').value=p.content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus();fetch('/api/prompts/'+id+'/use',{method:'POST'});showToast('已应用模板')}\nfunction showAddPromptModal(){var html='<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"promptName\" placeholder=\"模板名称\"></div><div class=\"form-group\"><label>分类</label><select id=\"promptCategory\"><option value=\"general\">通用</option><option value=\"writing\">写作</option><option value=\"coding\">编程</option><option value=\"translate\">翻译</option><option value=\"analysis\">分析</option><option value=\"creative\">创意</option></select></div><div class=\"form-group\"><label>内容</label><textarea id=\"promptContent\" rows=\"6\" placeholder=\"输入 Prompt 内容...\"></textarea></div><div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"savePrompt()\">保存</button><button class=\"btn btn-ghost\" onclick=\"closeModal(\\'promptModal\\')\">取消</button></div>';showCustomModal('新建 Prompt 模板',html,'promptModal')}\nfunction savePrompt(){var name=$('promptName').value.trim(),content=$('promptContent').value.trim(),category=$('promptCategory').value;if(!name||!content){alert('请填写名称和内容');return}api('/api/prompts',{method:'POST',body:JSON.stringify({name:name,content:content,category:category})}).then(function(){closeModal('promptModal');loadPrompts();showToast('模板已保存')}).catch(function(e){alert('保存失败: '+e.message)})}\nfunction showCustomModal(title,content,id){var modal=document.createElement('div');modal.id=id;modal.className='modal show';modal.innerHTML='<div class=\"modal-content\"><div class=\"modal-header\"><h3>'+title+'</h3><span style=\"cursor:pointer;font-size:20px\" onclick=\"closeModal(\\''+id+'\\')\">&times;</span></div><div class=\"modal-body\">'+content+'</div></div>';document.body.appendChild(modal)}\nfunction closeModal(id){var m=document.getElementById(id);if(m)m.remove()}\nfunction showPromptMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"editPrompt('+id+')\">✏️ 编辑</div><div onclick=\"deletePrompt('+id+')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:100px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction deletePrompt(id){if(!confirm('确定删除?'))return;api('/api/prompts/'+id,{method:'DELETE'}).then(function(){loadPrompts();showToast('已删除')}).catch(function(e){alert('删除失败: '+e.message)})}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\nconsole.log('🤖 AI Hub v1.8.0');\n</script>\n</body>\n</html>\n"}, "a223a03d294cc10028b0aa9a4889d56f979bb90c": {"t": 1785765486.7476628, "n": 154032, "h": "b37d27fdfbb6a15e", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n<div class=\"nav-item\" data-page=\"compare\"><span class=\"nav-item-icon\">⚖️</span> 模型对比</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 模型对比页 -->\n<div id=\"page-compare\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚖️</span> 模型对比</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">同时向多个模型发送相同问题,对比回答质量和速度</p>\n<div class=\"form-group\">\n<label>问题</label>\n<textarea id=\"compareQuestion\" rows=\"3\" placeholder=\"输入要对比的问题...\">请用一句话解释什么是人工智能</textarea>\n</div>\n<div class=\"form-group\">\n<label>选择模型 (最多5个)</label>\n<div id=\"compareModelList\" style=\"display:flex;flex-wrap:wrap;gap:8px;margin-top:8px\"></div>\n</div>\n<button class=\"btn btn-primary\" onclick=\"runCompare()\">🚀 开始对比</button>\n<button class=\"btn btn-ghost\" onclick=\"initCompareModels()\" style=\"margin-left:8px\">🔄 刷新模型</button>\n</div>\n<div class=\"settings-section\" id=\"compareResults\" style=\"display:none\">\n<h4><span>📊</span> 对比结果</h4>\n<div id=\"compareResultsContent\"></div>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){alert('文件上传功能开发中')}\nfunction voiceInput(){alert('语音输入功能开发中')}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();initCompareModels();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// 模型对比\nvar selectedCompareModels=[];\nfunction initCompareModels(){var html='';providers.forEach(function(p){if(p.models&&p.models.length>0){p.models.slice(0,5).forEach(function(m){var id=p.id+'_'+m.id;var checked=selectedCompareModels.includes(id)?'checked':'';html+='<label style=\"display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg);border-radius:8px;cursor:pointer;font-size:13px\"><input type=\"checkbox\" onchange=\"toggleCompareModel(\\''+p.id+'\\',\\''+m.id+'\\',\\''+p.url+'\\',\\''+p.key+'\\')\" '+checked+'><span>'+p.name+'/'+m.name+'</span></label>'})}});$('compareModelList').innerHTML=html||'<span style=\"color:var(--text2)\">请先在模型服务中添加模型</span>'}\nfunction toggleCompareModel(pid,mid,url,key){var id=pid+'_'+mid;var idx=selectedCompareModels.findIndex(function(m){return m.id===id});if(idx>=0){selectedCompareModels.splice(idx,1)}else if(selectedCompareModels.length<5){selectedCompareModels.push({id:id,provider:pid,model:mid,custom_url:url,api_key:key})}}\nfunction runCompare(){var question=$('compareQuestion').value.trim();if(!question){alert('请输入问题');return}if(selectedCompareModels.length<2){alert('请至少选择2个模型');return}$('compareResults').style.display='block';$('compareResultsContent').innerHTML='<div style=\"text-align:center;padding:40px;color:var(--text2)\"><div class=\"message-loading\"><div class=\"dots\"><span></span><span></span><span></span></div></div><p style=\"margin-top:12px\">正在对比 '+selectedCompareModels.length+' 个模型...</p></div>';var models=selectedCompareModels.map(function(m){var p=providers.find(function(x){return x.id===m.provider});return{provider:m.provider,model:m.model,custom_url:p?p.url:'',api_key:p?p.key:''}});fetch('/api/compare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:question,models:models})}).then(function(r){return r.json()}).then(function(data){renderCompareResults(data)}).catch(function(e){$('compareResultsContent').innerHTML='<div style=\"color:var(--error);padding:20px\">对比失败: '+e.message+'</div>'})}\nfunction renderCompareResults(data){var html='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px\">';data.results.forEach(function(r){var statusColor=r.success?'var(--success)':'var(--error)';html+='<div style=\"background:var(--bg);border-radius:12px;padding:16px;border-left:4px solid '+statusColor+'\"><div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\"><strong>'+r.provider+'/'+r.model+'</strong><span style=\"font-size:12px;color:var(--text2)\">'+r.latency+'s</span></div>';if(r.success){html+='<div style=\"font-size:14px;line-height:1.6;max-height:200px;overflow-y:auto\">'+marked.parse(r.content)+'</div><div style=\"margin-top:12px;font-size:12px;color:var(--text2)\">Tokens: '+r.tokens+'</div>'}else{html+='<div style=\"color:var(--error)\">错误: '+r.error+'</div>'}html+='</div>'});html+='</div>';$('compareResultsContent').innerHTML=html}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\nconsole.log('🤖 AI Hub v1.8.0');\n</script>\n</body>\n</html>\n"}, "26e27e1a7f5ef1c6fdf52c9b052430b0061fce26": {"t": 1785765488.5332122, "n": 150074, "h": "2a18aa28f7eb080e", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n/* 移动端适配 */\n@media(max-width:768px){\n.nav{position:fixed;left:-220px;z-index:100;height:100vh;transition:left .3s}\n.nav.show{left:0}\n.sidebar{width:100%;position:fixed;left:-100%;z-index:99;height:100vh;transition:left .3s}\n.sidebar.show{left:0}\n.content{width:100%}\n.mobile-menu-btn{display:flex!important}\n.chat-input-box{flex-wrap:wrap}\n.chat-toolbar{flex-wrap:wrap;gap:4px}\n.chat-toolbar .btn{padding:6px 10px;font-size:11px}\n.message{max-width:95%}\n.settings-panel{padding:12px}\n.form-row{flex-direction:column}\n}\n@media(min-width:769px){.mobile-menu-btn{display:none!important}}\n.mobile-menu-btn{position:fixed;top:12px;left:12px;z-index:101;width:40px;height:40px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;display:none;align-items:center;justify-content:center;cursor:pointer;font-size:20px}\n.mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:98;display:none}\n.mobile-overlay.show{display:block}\n</style>\n</head>\n<body>\n<div class=\"mobile-menu-btn\" onclick=\"toggleMobileNav()\">☰</div>\n<div class=\"mobile-overlay\" onclick=\"closeMobileMenus()\"></div>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"estimateTokens()\" title=\"估算 Token\">🔢</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showSearchModal()\" title=\"搜索 Ctrl+K\">🔍</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleTheme()\" title=\"切换主题 Ctrl+D\">🌓</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"shareChat()\" title=\"分享对话\">🔗 分享</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){alert('文件上传功能开发中')}\nfunction voiceInput(){alert('语音输入功能开发中')}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\n// 快捷键\ndocument.addEventListener('keydown',function(e){\nif((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}\nif((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}\nif((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}\nif((e.ctrlKey||e.metaKey)&&e.key==='k'){e.preventDefault();showSearchModal()}\nif((e.ctrlKey||e.metaKey)&&e.key==='d'){e.preventDefault();toggleTheme()}\nif((e.ctrlKey||e.metaKey)&&e.shiftKey&&e.key==='E'){e.preventDefault();exportChat('md')}\nif(e.key==='Escape'){document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')});hideSearchModal()}\n});\n// 主题切换\nfunction toggleTheme(){var current=document.documentElement.getAttribute('data-theme');var newTheme=current==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',newTheme);localStorage.setItem('theme',newTheme);showToast(newTheme==='light'?'☀️ 亮色模式':'🌙 暗色模式')}\nfunction initTheme(){var saved=localStorage.getItem('theme');if(saved)document.documentElement.setAttribute('data-theme',saved)}\ninitTheme();\n// 全局搜索\nvar searchModal=null;\nfunction showSearchModal(){if(!searchModal){searchModal=document.createElement('div');searchModal.innerHTML='<div style=\"position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:2000;display:flex;align-items:flex-start;justify-content:center;padding-top:100px\" onclick=\"if(event.target===this)hideSearchModal()\"><div style=\"background:var(--bg2);border-radius:16px;width:90%;max-width:600px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,0.3)\"><div style=\"padding:16px;border-bottom:1px solid var(--border)\"><input type=\"text\" id=\"globalSearchInput\" placeholder=\"搜索对话内容... (Ctrl+K)\" style=\"width:100%;padding:12px 16px;border:none;background:var(--bg);border-radius:8px;color:var(--text);font-size:16px\" oninput=\"doGlobalSearch(this.value)\"></div><div id=\"searchResults\" style=\"max-height:400px;overflow-y:auto;padding:8px\"></div><div style=\"padding:12px 16px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)\">💡 Ctrl+D 切换主题 · Ctrl+N 新建对话 · Ctrl+Shift+E 导出</div></div></div>';document.body.appendChild(searchModal)}searchModal.style.display='block';setTimeout(function(){$('globalSearchInput').focus()},100)}\nfunction hideSearchModal(){if(searchModal)searchModal.style.display='none'}\nfunction doGlobalSearch(q){if(!q||q.length<2){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">输入关键词搜索...</div>';return}var results=[];chats.forEach(function(c){c.messages.forEach(function(m,i){if(typeof m.content==='string'&&m.content.toLowerCase().includes(q.toLowerCase())){results.push({chatId:c.id,chatTitle:c.title,msgIndex:i,role:m.role,content:m.content,match:q})}})});if(results.length===0){$('searchResults').innerHTML='<div style=\"padding:40px;text-align:center;color:var(--text2)\">未找到结果</div>';return}var html=results.slice(0,20).map(function(r){var snippet=r.content.substring(0,150).replace(new RegExp('('+q+')','gi'),'<mark style=\"background:var(--warning);color:#000;padding:0 2px;border-radius:2px\">$1</mark>');return'<div style=\"padding:12px 16px;cursor:pointer;border-bottom:1px solid var(--border)\" onclick=\"goToSearchResult(\\''+r.chatId+'\\','+r.msgIndex+')\" onmouseover=\"this.style.background=\\'var(--bg3)\\'\" onmouseout=\"this.style.background=\\'\\'\"><div style=\"font-size:13px;color:var(--text2);margin-bottom:4px\">'+(r.role==='user'?'👤':'🤖')+' '+r.chatTitle+'</div><div style=\"font-size:14px;line-height:1.5\">'+snippet+'...</div></div>'}).join('');$('searchResults').innerHTML=html}\nfunction goToSearchResult(chatId,msgIndex){hideSearchModal();selectChat(chatId);setTimeout(function(){var msgs=document.querySelectorAll('.message');if(msgs[msgIndex]){msgs[msgIndex].scrollIntoView({behavior:'smooth',block:'center'});msgs[msgIndex].style.background='var(--accent)';msgs[msgIndex].style.transition='background 0.3s';setTimeout(function(){msgs[msgIndex].style.background=''},1500)}},200)}\n// Token 估算\nfunction estimateTokens(){var text=$('chatInput').value;if(!text)return;fetch('/api/tokens/estimate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({text:text,model:$('chatModel').value})}).then(function(r){return r.json()}).then(function(data){showToast('预估 '+data.tokens+' tokens'+(data.estimated?' (估算)':''))}).catch(function(e){console.error(e)})}\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\n// 分享对话\nfunction shareChat(){if(!authToken){alert('请先登录');return}if(!currentChatId){alert('请先选择对话');return}api('/api/conversations/'+currentChatId+'/share',{method:'POST'}).then(function(data){var url=window.location.origin+data.url;if(navigator.clipboard){navigator.clipboard.writeText(url);showToast('分享链接已复制!')}prompt('分享链接 (7天有效):',url)}).catch(function(e){alert('分享失败: '+e.message)})}\n// 移动端菜单\nfunction toggleMobileNav(){document.querySelector('.nav').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction toggleMobileSidebar(){document.querySelector('.sidebar').classList.toggle('show');document.querySelector('.mobile-overlay').classList.toggle('show')}\nfunction closeMobileMenus(){document.querySelector('.nav').classList.remove('show');document.querySelector('.sidebar').classList.remove('show');document.querySelector('.mobile-overlay').classList.remove('show')}\nconsole.log('🤖 AI Hub v1.8.0');\n</script>\n</body>\n</html>\n"}, "1ed3f151f35561d318ec20879a6591bd1ffecbe9": {"t": 1785765490.7023888, "n": 143713, "h": "1d9bad61be87e74b", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/matlab.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n</style>\n</head>\n<body>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n<div class=\"nav-item\" data-page=\"stats\"><span class=\"nav-item-icon\">📊</span> 使用统计</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<div style=\"position:relative;display:inline-block\"><button class=\"btn btn-ghost btn-sm\" onclick=\"this.nextElementSibling.style.display=this.nextElementSibling.style.display==='block'?'none':'block'\">📥 导出</button><div style=\"display:none;position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:100px;z-index:100\"><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('txt');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📄 TXT</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('md');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📝 Markdown</div><div style=\"padding:8px 12px;cursor:pointer;border-radius:4px;font-size:12px\" onclick=\"exportChat('json');this.parentElement.style.display='none'\" onmouseover=\"this.style.background='var(--bg3)'\" onmouseout=\"this.style.background=''\">📋 JSON</div></div></div>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><div style=\"position:relative\"><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\" style=\"padding-right:40px\"><button type=\"button\" onclick=\"toggleProviderKey()\" id=\"togglePKeyBtn\" style=\"position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px\">👁️</button></div></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- 使用统计页 -->\n<div id=\"page-stats\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📊</span> 使用统计</h4>\n<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px\">\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--accent)\" id=\"statTodayCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">今日调用</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--success)\" id=\"statTotalCalls\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">总调用次数</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--warning)\" id=\"statTokensInput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输入 Tokens</div>\n</div>\n<div style=\"background:var(--bg);padding:20px;border-radius:12px;text-align:center\">\n<div style=\"font-size:28px;font-weight:700;color:var(--error)\" id=\"statTokensOutput\">0</div>\n<div style=\"font-size:12px;color:var(--text2);margin-top:4px\">输出 Tokens</div>\n</div>\n</div>\n<button class=\"btn btn-ghost\" onclick=\"loadStats()\">🔄 刷新统计</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📈</span> 模型使用排行</h4>\n<div id=\"modelStatsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无数据</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 最近调用日志</h4>\n<div id=\"apiLogsTable\" style=\"background:var(--bg);border-radius:8px;overflow:hidden;max-height:400px;overflow-y:auto\">\n<div style=\"padding:20px;text-align:center;color:var(--text2)\">暂无日志</div>\n</div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active');if(n.dataset.page==='stats')loadStats()}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(format){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;format=format||'txt';if(format==='json'){var data={id:chat.id,title:chat.title,messages:chat.messages,created:chat.created};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.json';a.click()}else if(format==='md'){var lines=['# '+(chat.title||'对话记录'),'','---',''];chat.messages.forEach(function(m){lines.push('### '+(m.role==='user'?'👤 用户':'🤖 助手'));lines.push('');lines.push(m.content);lines.push('')});var blob=new Blob([lines.join('\\n')],{type:'text/markdown'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.md';a.click()}else{var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}}\n// 使用统计\nfunction loadStats(){if(!authToken){$('statTodayCalls').textContent='请登录';return}api('/api/stats').then(function(data){$('statTodayCalls').textContent=data.today_calls||0;$('statTotalCalls').textContent=data.total_calls||0;$('statTokensInput').textContent=formatNumber(data.tokens_input||0);$('statTokensOutput').textContent=formatNumber(data.tokens_output||0);if(data.model_stats&&data.model_stats.length>0){var html='<table style=\"width:100%;border-collapse:collapse\"><tr style=\"background:var(--bg2)\"><th style=\"padding:12px;text-align:left\">模型</th><th style=\"padding:12px;text-align:right\">调用次数</th><th style=\"padding:12px;text-align:right\">Tokens</th></tr>';data.model_stats.forEach(function(s){html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:12px\">'+s.provider+'/'+s.model+'</td><td style=\"padding:12px;text-align:right\">'+s.calls+'</td><td style=\"padding:12px;text-align:right\">'+formatNumber(s.tokens||0)+'</td></tr>'});html+='</table>';$('modelStatsTable').innerHTML=html}loadLogs()}).catch(function(e){console.error('加载统计失败:',e)})}\nfunction loadLogs(){api('/api/logs?limit=30').then(function(logs){if(logs&&logs.length>0){var html='<table style=\"width:100%;border-collapse:collapse;font-size:12px\"><tr style=\"background:var(--bg2)\"><th style=\"padding:10px;text-align:left\">时间</th><th style=\"padding:10px\">模型</th><th style=\"padding:10px;text-align:right\">Tokens</th><th style=\"padding:10px;text-align:right\">耗时</th><th style=\"padding:10px\">状态</th></tr>';logs.forEach(function(l){var statusColor=l.status==='success'?'var(--success)':'var(--error)';html+='<tr style=\"border-top:1px solid var(--border)\"><td style=\"padding:10px\">'+(l.created_at||'').slice(5,16)+'</td><td style=\"padding:10px;text-align:center\">'+l.model+'</td><td style=\"padding:10px;text-align:right\">'+(l.tokens_input+l.tokens_output)+'</td><td style=\"padding:10px;text-align:right\">'+(l.latency_ms/1000).toFixed(1)+'s</td><td style=\"padding:10px;text-align:center;color:'+statusColor+'\">'+(l.status==='success'?'✓':'✗')+'</td></tr>'});html+='</table>';$('apiLogsTable').innerHTML=html}}).catch(function(e){console.error('加载日志失败:',e)})}\nfunction formatNumber(n){if(n>=1000000)return(n/1000000).toFixed(1)+'M';if(n>=1000)return(n/1000).toFixed(1)+'K';return n}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction toggleProviderKey(){var input=$('pKey'),btn=$('togglePKeyBtn');if(input.type==='password'){input.type='text';btn.textContent='🙈'}else{input.type='password';btn.textContent='👁️'}}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){alert('文件上传功能开发中')}\nfunction voiceInput(){alert('语音输入功能开发中')}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\ndocument.addEventListener('keydown',function(e){if((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}if((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}if((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}if(e.key==='Escape')document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')})});\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\nconsole.log('🤖 AI Hub v1.7.2');\n</script>\n</body>\n</html>\n"}, "fdb0e58f76387f6cada9ff8b104e262ea956090f": {"t": 1785765492.6270921, "n": 136995, "h": "7b87c1d3e93d9e37", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n</style>\n</head>\n<body>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportChat()\">📥 导出</button>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\"></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active')}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var contentText=typeof m.content==='string'?m.content:(m.content||'');var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(contentText):escapeHtml(contentText))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){alert('文件上传功能开发中')}\nfunction voiceInput(){alert('语音输入功能开发中')}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\ndocument.addEventListener('keydown',function(e){if((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}if((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}if((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}if(e.key==='Escape')document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')})});\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\nconsole.log('🤖 AI Hub v1.7.2');\n</script>\n</body>\n</html>\n"}, "3338265f318f4dc2a44c71bb3fc880637e924319": {"t": 1785765494.4768536, "n": 136921, "h": "adad6d000fe3e747", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.image-preview-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg3);border-radius:8px;margin-right:8px}\n.image-preview-item img{width:60px;height:60px;object-fit:cover;border-radius:6px}\n.image-preview-item .remove-btn{cursor:pointer;color:var(--text2);font-size:16px}\n.image-preview-item .remove-btn:hover{color:var(--error)}\n.message-image{max-width:300px;max-height:200px;border-radius:8px;margin:8px 0;cursor:pointer}\n.message-image:hover{opacity:0.9}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n</style>\n</head>\n<body>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div id=\"imagePreview\" style=\"display:none;padding:8px 0;margin-bottom:8px\"></div>\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportChat()\">📥 导出</button>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n<input type=\"file\" id=\"imageInput\" accept=\"image/*\" style=\"display:none\" onchange=\"handleImageSelect(event)\">\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\"></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active')}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var imagesHtml='';if(m.images&&m.images.length>0){m.images.forEach(function(img){imagesHtml+='<img src=\"'+img.data+'\" class=\"message-image\" onclick=\"showImageModal(this.src)\" alt=\"上传的图片\">'});}var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+imagesHtml+(m.role==='assistant'?marked.parse(m.content):escapeHtml(m.content))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction showImageModal(src){var modal=document.createElement('div');modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,0.9);display:flex;align-items:center;justify-content:center;z-index:2000;cursor:pointer';modal.innerHTML='<img src=\"'+src+'\" style=\"max-width:90%;max-height:90%;border-radius:8px\">';modal.onclick=function(){modal.remove()};document.body.appendChild(modal)}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text&&pendingImages.length===0)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}var userMsg={role:'user',content:text};if(pendingImages.length>0){userMsg.images=pendingImages.slice();pendingImages=[];renderImagePreview()}chat.messages.push(userMsg);if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){if(m.images&&m.images.length>0){var contentArr=[{type:'text',text:m.content||'请描述这张图片'}];m.images.forEach(function(img){contentArr.push({type:'image_url',image_url:{url:img.data}})});return{role:m.role,content:contentArr}}return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nvar pendingImages=[];\nfunction uploadImage(){$('imageInput').click()}\nfunction handleImageSelect(e){var file=e.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){alert('请选择图片文件');return}if(file.size>10*1024*1024){alert('图片大小不能超过10MB');return}var reader=new FileReader();reader.onload=function(ev){var base64=ev.target.result;pendingImages.push({name:file.name,data:base64,type:file.type});renderImagePreview()};reader.readAsDataURL(file);e.target.value=''}\nfunction renderImagePreview(){var container=$('imagePreview');if(pendingImages.length===0){container.style.display='none';container.innerHTML='';return}container.style.display='block';var html=pendingImages.map(function(img,i){return'<div class=\"image-preview-item\"><img src=\"'+img.data+'\" alt=\"'+img.name+'\"><span>'+img.name.slice(0,15)+(img.name.length>15?'...':'')+'</span><span class=\"remove-btn\" onclick=\"removeImage('+i+')\">✕</span></div>'}).join('');container.innerHTML=html}\nfunction removeImage(index){pendingImages.splice(index,1);renderImagePreview()}\nfunction uploadFile(){alert('文件上传功能开发中')}\nfunction voiceInput(){alert('语音输入功能开发中')}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\ndocument.addEventListener('keydown',function(e){if((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}if((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}if((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}if(e.key==='Escape')document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')})});\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\nconsole.log('🤖 AI Hub v1.7.2');\n</script>\n</body>\n</html>\n"}, "975d728efc120f519138897613b7e7d8e9c3dfb5": {"t": 1785765496.4126031, "n": 134275, "h": "eaaa08e341c73156", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.message-loading{display:flex;align-items:center;gap:8px;color:var(--text2);font-size:13px}\n.message-loading .dots{display:flex;gap:4px}\n.message-loading .dots span{width:6px;height:6px;background:var(--accent);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}\n.message-loading .dots span:nth-child(1){animation-delay:-0.32s}\n.message-loading .dots span:nth-child(2){animation-delay:-0.16s}\n@keyframes bounce{0%,80%,100%{transform:scale(0)}40%{transform:scale(1)}}\n.message-timer{font-size:12px;color:var(--accent);margin-left:8px}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n</style>\n</head>\n<body>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportChat()\">📥 导出</button>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\"></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active')}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var timeInfo=m.time?'<div class=\"message-time\">⏱️ '+m.time+'</div>':'';var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+(m.role==='assistant'?marked.parse(m.content):escapeHtml(m.content))+'</div>'+timeInfo+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nvar chatTimer=null,chatStartTime=0;\nfunction updateTimer(){var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var timerEl=document.querySelector('.message-timer');if(timerEl)timerEl.textContent=elapsed+'s'}\nfunction showLoading(){var model=$('chatModel').value||'模型';$('chatMessages').innerHTML+='<div class=\"message assistant\" id=\"loadingMsg\"><div class=\"message-content\"><div class=\"message-loading\"><span>🤖 '+model+' 正在思考</span><div class=\"dots\"><span></span><span></span><span></span></div><span class=\"message-timer\">0.0s</span></div></div></div>';$('chatMessages').scrollTop=$('chatMessages').scrollHeight;chatStartTime=Date.now();chatTimer=setInterval(updateTimer,100)}\nfunction hideLoading(){if(chatTimer){clearInterval(chatTimer);chatTimer=null}var el=$('loadingMsg');if(el)el.remove()}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}chat.messages.push({role:'user',content:text});if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();showLoading();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};if(stream){var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){hideLoading();chat.messages.push({role:'assistant',content:''});renderMessages();var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){}}});read()})}read()}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){hideLoading();var elapsed=((Date.now()-chatStartTime)/1000).toFixed(1);var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content,time:elapsed+'s'})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){hideLoading();chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nfunction uploadImage(){alert('图片上传功能开发中')}\nfunction uploadFile(){alert('文件上传功能开发中')}\nfunction voiceInput(){alert('语音输入功能开发中')}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\ndocument.addEventListener('keydown',function(e){if((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}if((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}if((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}if(e.key==='Escape')document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')})});\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\nconsole.log('🤖 AI Hub v1.7.2');\n</script>\n</body>\n</html>\n"}, "85686727648ab3d8809759ea820b8dced4067185": {"t": 1785765498.201652, "n": 132887, "h": "e66b8114c54ab7a4", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n</style>\n</head>\n<body>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportChat()\">📥 导出</button>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\"></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📂</span> 本地 Git 仓库</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置本地 Git 仓库路径,可将代码推送到本地仓库</p>\n<div class=\"form-group\"><label>仓库路径</label><input type=\"text\" id=\"localGitPath\" placeholder=\"D:\\projects\\my-repo\" style=\"font-family:monospace\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testLocalGit()\">🔍 测试仓库</button><button class=\"btn btn-primary\" onclick=\"saveLocalGitSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active')}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+(m.role==='assistant'?marked.parse(m.content):escapeHtml(m.content))+'</div>'+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}chat.messages.push({role:'user',content:text});if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;console.log('Provider:',p?p.name:'none','Key length:',key?key.length:0,'URL:',p?p.url:'none');var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};console.log('Sending payload:',payload);if(stream){chat.messages.push({role:'assistant',content:''});renderMessages();var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);console.log('Stream chunk:',parsed);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){console.log('Parse error:',e,data)}}});read()})}read()}).catch(function(e){chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nfunction uploadImage(){alert('图片上传功能开发中')}\nfunction uploadFile(){alert('文件上传功能开发中')}\nfunction voiceInput(){alert('语音输入功能开发中')}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);var choice=confirm('推送到 GitHub?\\n\\n点击\"确定\"推送到 GitHub\\n点击\"取消\"推送到本地 Git');if(choice){pushToGithub(content,'code'+ext,'Add code from AI conversation')}else{pushToLocalGit(content,'code'+ext,'Add code from AI conversation')}}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 本地 Git\nvar localGitSettings=JSON.parse(localStorage.getItem('localGitSettings')||'{}');\nfunction loadLocalGitSettings(){if(localGitSettings.repoPath&&$('localGitPath'))$('localGitPath').value=localGitSettings.repoPath}\nfunction saveLocalGitSettings(){localGitSettings={repoPath:$('localGitPath').value.trim()};localStorage.setItem('localGitSettings',JSON.stringify(localGitSettings));alert('本地 Git 设置已保存')}\nfunction testLocalGit(){var path=$('localGitPath').value.trim();if(!path){alert('请填写仓库路径');return}fetch('/api/git/local/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:path})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 仓库有效\\n远程: '+(data.remotes||'无'))}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToLocalGit(content,filename,message){if(!localGitSettings.repoPath){alert('请先在数据设置中配置本地 Git 仓库路径');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/local/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_path:localGitSettings.repoPath,file_path:filePath,content:content,commit_message:commitMsg})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ '+data.message)}else{alert('✗ 失败: '+(data.detail||data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();loadLocalGitSettings();\ndocument.addEventListener('keydown',function(e){if((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}if((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}if((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}if(e.key==='Escape')document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')})});\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\nconsole.log('🤖 AI Hub v1.7.2');\n</script>\n</body>\n</html>\n"}, "6b4bc8f97c01bb37e61ecdcf9814bc14b0f9c0df": {"t": 1785765500.3714209, "n": 130690, "h": "fd9868b99183ac13", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n</style>\n</head>\n<body>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportChat()\">📥 导出</button>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\"></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🐙</span> GitHub 推送</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">配置 GitHub 仓库,可将 AI 生成的代码直接推送到仓库</p>\n<div class=\"form-group\"><label>仓库地址</label><input type=\"text\" id=\"githubRepoUrl\" placeholder=\"https://github.com/username/repo\" style=\"font-family:monospace\"></div>\n<div class=\"form-group\"><label>Personal Access Token</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"githubToken\" placeholder=\"ghp_xxxxxxxxxxxx\" style=\"flex:1;font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('githubToken')\">👁️</button></div><a href=\"https://github.com/settings/tokens/new\" target=\"_blank\" style=\"font-size:12px;color:var(--accent)\">点击这里获取 Token (需要 repo 权限)</a></div>\n<div class=\"form-group\"><label>默认分支</label><input type=\"text\" id=\"githubBranch\" value=\"main\" style=\"width:150px\"></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"testGithub()\">🔍 测试连接</button><button class=\"btn btn-primary\" onclick=\"saveGithubSettings()\">💾 保存</button></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active')}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button><button class=\"message-action-btn\" onclick=\"pushMessageToGithub('+i+')\" title=\"推送到GitHub\">🐙</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+(m.role==='assistant'?marked.parse(m.content):escapeHtml(m.content))+'</div>'+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}chat.messages.push({role:'user',content:text});if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;console.log('Provider:',p?p.name:'none','Key length:',key?key.length:0,'URL:',p?p.url:'none');var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};console.log('Sending payload:',payload);if(stream){chat.messages.push({role:'assistant',content:''});renderMessages();var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);console.log('Stream chunk:',parsed);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){console.log('Parse error:',e,data)}}});read()})}read()}).catch(function(e){chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nfunction uploadImage(){alert('图片上传功能开发中')}\nfunction uploadFile(){alert('文件上传功能开发中')}\nfunction voiceInput(){alert('语音输入功能开发中')}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// GitHub 推送\nvar githubSettings=JSON.parse(localStorage.getItem('githubSettings')||'{}');\nfunction loadGithubSettings(){if(githubSettings.repoUrl)$('githubRepoUrl').value=githubSettings.repoUrl;if(githubSettings.token)$('githubToken').value=githubSettings.token;if(githubSettings.branch)$('githubBranch').value=githubSettings.branch}\nfunction saveGithubSettings(){githubSettings={repoUrl:$('githubRepoUrl').value.trim(),token:$('githubToken').value.trim(),branch:$('githubBranch').value.trim()||'main'};localStorage.setItem('githubSettings',JSON.stringify(githubSettings));alert('GitHub 设置已保存')}\nfunction testGithub(){var url=$('githubRepoUrl').value.trim(),token=$('githubToken').value.trim();if(!url||!token){alert('请填写仓库地址和 Token');return}fetch('/api/git/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:url,token:token})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功: '+data.repo)}else{alert('✗ 失败: '+data.error)}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushToGithub(content,filename,message){if(!githubSettings.repoUrl||!githubSettings.token){alert('请先在数据设置中配置 GitHub');return}var filePath=prompt('文件路径:',filename||'code.txt');if(!filePath)return;var commitMsg=prompt('提交信息:',message||'Add code from AI Hub');if(!commitMsg)return;fetch('/api/git/push',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({repo_url:githubSettings.repoUrl,token:githubSettings.token,file_path:filePath,content:content,commit_message:commitMsg,branch:githubSettings.branch||'main'})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 推送成功!\\n'+data.url)}else{alert('✗ 失败: '+(data.detail||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction pushMessageToGithub(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var content=chat.messages[index].content;var codeMatch=content.match(/```[\\w]*\\n([\\s\\S]*?)```/);if(codeMatch){content=codeMatch[1]}var ext=detectFileExtension(content);pushToGithub(content,'code'+ext,'Add code from AI conversation')}\nfunction detectFileExtension(content){if(content.includes('def ')||content.includes('import ')||content.includes('print('))return'.py';if(content.includes('function ')||content.includes('const ')||content.includes('let '))return'.js';if(content.includes('<html')||content.includes('<!DOCTYPE'))return'.html';if(content.includes('package ')||content.includes('public class'))return'.java';if(content.includes('#include'))return'.cpp';return'.txt'}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();loadGithubSettings();\ndocument.addEventListener('keydown',function(e){if((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}if((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}if((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}if(e.key==='Escape')document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')})});\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\nconsole.log('🤖 AI Hub v1.7.2');\n</script>\n</body>\n</html>\n"}, "1fa35a48bffcb63ef014d77c31b25e416a2562e2": {"t": 1785765502.1803467, "n": 126873, "h": "fc82f8d08d248f51", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>AI Hub</title>\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n<style>\n:root{--bg:#0f0f1a;--bg2:#1a1a2e;--bg3:#252542;--text:#e8e8f0;--text2:#8888a0;--accent:#6366f1;--accent2:#818cf8;--success:#22c55e;--warning:#f59e0b;--error:#ef4444;--border:#2d2d4a}\n[data-theme=\"light\"]{--bg:#f8f9fa;--bg2:#ffffff;--bg3:#e9ecef;--text:#212529;--text2:#6c757d;--border:#dee2e6}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex;overflow:hidden}\n::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\n.nav{width:220px;background:var(--bg2);display:flex;flex-direction:column;border-right:1px solid var(--border);flex-shrink:0}\n.nav-header{padding:20px 16px;border-bottom:1px solid var(--border)}\n.nav-logo{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600}\n.nav-section{padding:12px 8px}\n.nav-section-title{font-size:11px;color:var(--text2);padding:8px 12px;text-transform:uppercase;letter-spacing:1px}\n.nav-item{display:flex;align-items:center;gap:12px;padding:10px 16px;border-radius:8px;cursor:pointer;font-size:14px;color:var(--text2);transition:all .15s;margin-bottom:2px}\n.nav-item:hover{background:var(--bg3);color:var(--text)}\n.nav-item.active{background:var(--accent);color:#fff}\n.nav-item-icon{width:20px;text-align:center;font-size:16px}\n.nav-divider{height:1px;background:var(--border);margin:8px 16px}\n.nav-bottom{margin-top:auto;padding:12px 8px;border-top:1px solid var(--border)}\n.main{flex:1;display:flex;overflow:hidden}\n.page{display:none;flex:1;overflow:hidden}\n.page.active{display:flex}\n.sidebar{width:280px;background:var(--bg);border-right:1px solid var(--border);display:flex;flex-direction:column}\n.sidebar-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.sidebar-header h3{font-size:15px;font-weight:600}\n.sidebar-list{flex:1;overflow-y:auto;padding:8px}\n.sidebar-item{display:flex;align-items:center;padding:12px;border-radius:10px;margin-bottom:4px;cursor:pointer;transition:all .15s}\n.sidebar-item:hover{background:var(--bg3)}\n.sidebar-item.active{background:var(--accent);color:#fff}\n.sidebar-item-icon{width:36px;height:36px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:12px;font-size:16px}\n.sidebar-item.active .sidebar-item-icon{background:rgba(255,255,255,0.2)}\n.sidebar-item-info{flex:1;min-width:0}\n.sidebar-item-title{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sidebar-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.sidebar-item.active .sidebar-item-desc{color:rgba(255,255,255,0.7)}\n.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s;display:inline-flex;align-items:center;gap:6px}\n.btn-primary{background:var(--accent);color:#fff}\n.btn-primary:hover{background:var(--accent2)}\n.btn-success{background:var(--success);color:#fff}\n.btn-danger{background:var(--error);color:#fff}\n.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)}\n.btn-ghost:hover{background:var(--bg3);color:var(--text)}\n.btn-sm{padding:6px 12px;font-size:12px}\n.btn-icon{width:36px;height:36px;padding:0;justify-content:center}\n.content{flex:1;display:flex;flex-direction:column;overflow:hidden}\n.content-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px}\n.content-body{flex:1;overflow-y:auto;padding:24px}\n.chat-messages{flex:1;overflow-y:auto;padding:24px}\n.message{max-width:85%;margin-bottom:20px}\n.message.user{margin-left:auto}\n.message-content{padding:14px 18px;border-radius:16px;line-height:1.7;font-size:14px}\n.message.user .message-content{background:var(--accent);color:#fff;border-bottom-right-radius:4px}\n.message.assistant .message-content{background:var(--bg2);border-bottom-left-radius:4px}\n.message.error .message-content{background:var(--error)}\n.message-content pre{margin:12px 0;padding:14px;background:var(--bg);border-radius:8px;overflow-x:auto}\n.message-content code{font-family:Consolas,monospace;font-size:13px}\n.message-content p{margin:8px 0}\n.message-actions{display:flex;gap:4px;margin-top:8px;opacity:0;transition:opacity .15s}\n.message:hover .message-actions{opacity:1}\n.message-action-btn{padding:4px 8px;border:none;background:var(--bg3);color:var(--text2);border-radius:4px;cursor:pointer;font-size:12px;transition:all .15s}\n.message-action-btn:hover{background:var(--accent);color:#fff}\n.message-time{font-size:11px;color:var(--text2);margin-top:4px}\n.chat-input-area{padding:16px 24px;border-top:1px solid var(--border);background:var(--bg2)}\n.chat-input-box{display:flex;gap:12px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:8px 12px}\n.chat-input-box textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:14px;resize:none;max-height:150px;line-height:1.5}\n.chat-input-box textarea:focus{outline:none}\n.chat-toolbar{display:flex;gap:8px;margin-bottom:12px}\n.settings-panel{width:100%;max-width:800px;margin:0 auto}\n.settings-section{background:var(--bg2);border-radius:16px;padding:24px;margin-bottom:20px}\n.settings-section h4{font-size:16px;margin-bottom:16px;display:flex;align-items:center;gap:10px}\n.form-group{margin-bottom:20px}\n.form-group label{display:block;font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:500}\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-size:14px}\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent)}\n.form-row{display:flex;gap:12px}\n.form-row>*{flex:1}\n.card{background:var(--bg2);border-radius:12px;padding:20px;margin-bottom:16px}\n.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}\n.card-title{font-size:15px;font-weight:600}\n.list-item{display:flex;align-items:center;padding:14px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.list-item-icon{width:40px;height:40px;border-radius:10px;background:var(--bg3);display:flex;align-items:center;justify-content:center;margin-right:14px;font-size:18px}\n.list-item-content{flex:1}\n.list-item-title{font-size:14px;font-weight:500}\n.list-item-desc{font-size:12px;color:var(--text2);margin-top:2px}\n.list-item-actions{display:flex;gap:8px}\n.modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;z-index:1000}\n.modal.show{display:flex}\n.modal-content{background:var(--bg2);border-radius:16px;width:90%;max-width:500px;max-height:90vh;overflow:hidden}\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}\n.modal-header h3{font-size:18px}\n.modal-body{padding:24px;overflow-y:auto;max-height:60vh}\n.empty-state{text-align:center;padding:60px 20px;color:var(--text2)}\n.empty-state span{font-size:48px;display:block;margin-bottom:16px}\n.switch{position:relative;width:44px;height:24px;display:inline-block}\n.switch input{opacity:0;width:0;height:0}\n.switch-slider{position:absolute;cursor:pointer;inset:0;background:var(--bg3);border-radius:24px;transition:.3s}\n.switch-slider:before{position:absolute;content:\"\";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}\n.switch input:checked+.switch-slider{background:var(--accent)}\n.switch input:checked+.switch-slider:before{transform:translateX(20px)}\n.tag{display:inline-block;padding:4px 10px;border-radius:6px;font-size:12px;background:var(--bg3);color:var(--text2)}\n.tag-primary{background:rgba(99,102,241,0.2);color:var(--accent2)}\n.price-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}\n.price-card{background:var(--bg3);border-radius:16px;padding:24px;text-align:center;border:2px solid transparent;cursor:pointer}\n.price-card:hover{border-color:var(--accent)}\n.price-card h4{font-size:18px;margin-bottom:8px}\n.price-card .price{font-size:32px;font-weight:700;color:var(--accent);margin:16px 0}\n.price-card .price span{font-size:14px;color:var(--text2)}\n.price-card ul{text-align:left;margin:20px 0;list-style:none}\n.price-card li{padding:6px 0;font-size:13px;color:var(--text2)}\n.price-card li::before{content:'✓';color:var(--success);margin-right:8px}\n.setting-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border)}\n.setting-row:last-child{border-bottom:none}\n.setting-row-label{font-size:14px}\n.setting-row-label small{display:block;font-size:12px;color:var(--text2);margin-top:4px}\n.slider-container{display:flex;align-items:center;gap:12px}\n.slider-container input[type=\"range\"]{width:150px;accent-color:var(--accent)}\n.slider-value{min-width:40px;text-align:right;font-size:14px;color:var(--accent)}\n.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:20px}\n.tab{padding:12px 20px;cursor:pointer;font-size:14px;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\n.assistant-card{display:flex;align-items:center;padding:16px;background:var(--bg);border-radius:12px;margin-bottom:12px;cursor:pointer;transition:all .15s}\n.assistant-card:hover{background:var(--bg3)}\n.assistant-card.active{background:var(--accent);color:#fff}\n.assistant-avatar{width:48px;height:48px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px;margin-right:14px}\n.assistant-info{flex:1}\n.assistant-name{font-size:15px;font-weight:500}\n.assistant-desc{font-size:12px;color:var(--text2);margin-top:4px}\n.assistant-card.active .assistant-desc{color:rgba(255,255,255,0.7)}\n.assistant-tag{padding:4px 8px;border-radius:4px;font-size:11px;background:var(--bg3);color:var(--text2)}\n.changelog{max-height:400px;overflow-y:auto}\n.changelog-item{padding:16px 0;border-bottom:1px solid var(--border)}\n.changelog-item:last-child{border-bottom:none}\n.changelog-version{font-size:16px;font-weight:600;color:var(--accent);margin-bottom:8px}\n.changelog-date{font-size:12px;color:var(--text2);margin-left:12px}\n.changelog-content{font-size:14px;color:var(--text2);line-height:1.8}\n.changelog-content li{margin:4px 0}\n.collapse-header{display:flex;align-items:center;justify-content:space-between;padding:14px 0;cursor:pointer;border-bottom:1px solid var(--border)}\n.collapse-header h5{font-size:14px;display:flex;align-items:center;gap:8px}\n.collapse-content{padding:16px 0;display:none}\n.collapse-content.show{display:block}\n.hotkey-row{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--border)}\n.hotkey-row:last-child{border-bottom:none}\n.hotkey-row span:first-child{font-size:14px}\n.hotkey-right{display:flex;align-items:center;gap:12px}\n.hotkey-key{font-size:13px;color:var(--text2);min-width:120px;text-align:right}\n.hotkey-info,.hotkey-lock{color:var(--text2);font-size:14px;cursor:pointer}\n.shortcut-item{display:flex;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}\n.shortcut-item:hover{background:var(--bg3);margin:0 -16px;padding:12px 16px}\n.shortcut-item:last-child{border-bottom:none}\n.shortcut-item-icon{font-size:18px;margin-right:12px}\n.shortcut-item-name{font-size:14px}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}\n.memory-item{display:flex;align-items:flex-start;padding:16px;background:var(--bg);border-radius:10px;margin-bottom:8px}\n.memory-item-content{flex:1;font-size:14px;line-height:1.6}\n.memory-item-meta{font-size:12px;color:var(--text2);margin-top:8px}\n.memory-item-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}\n.memory-item:hover .memory-item-actions{opacity:1}\n.mcp-market-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:var(--bg);border-radius:10px;cursor:pointer;transition:all .15s}\n.mcp-market-card:hover{background:var(--bg3)}\n.mcp-server-card{background:var(--bg);border-radius:10px;padding:16px;transition:all .15s}\n.mcp-server-card:hover{background:var(--bg3)}\n.mcp-server-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.mcp-server-desc{font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:12px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.mcp-server-tags{display:flex;gap:6px;flex-wrap:wrap}\n.mcp-add-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--bg3);border-radius:6px;cursor:pointer;font-size:16px;color:var(--text2)}\n.mcp-add-btn:hover{background:var(--accent);color:#fff}\n.settings-sidebar{width:200px;background:var(--bg);border-right:1px solid var(--border);padding:16px 8px;flex-shrink:0}\n.settings-sidebar-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text2);margin-bottom:2px}\n.settings-sidebar-item:hover{background:var(--bg3);color:var(--text)}\n.settings-sidebar-item.active{background:var(--accent);color:#fff}\n.settings-sidebar-title{font-size:11px;color:var(--text2);padding:12px 12px 8px;text-transform:uppercase;letter-spacing:1px}\n.theme-btn{width:60px;padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:12px;cursor:pointer;text-align:center}\n.theme-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n.color-picker{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .15s}\n.color-picker:hover{transform:scale(1.1)}\n.color-picker.active{border-color:#fff;box-shadow:0 0 0 2px var(--accent)}\n.hotkey-help-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg);border-radius:8px;font-size:13px}\n.hotkey-help-key{padding:4px 8px;background:var(--bg3);border-radius:4px;font-family:monospace;font-size:12px;color:var(--accent)}\n.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);padding:12px 24px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;z-index:2000;animation:fadeInUp .3s}\n@keyframes fadeInUp{from{opacity:0;transform:translateX(-50%) translateY(20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}\n.context-menu div{padding:8px 12px;cursor:pointer;font-size:13px;border-radius:4px}\n.context-menu div:hover{background:var(--bg3)}\n.sidebar-item:hover .chat-delete-btn{opacity:1!important}\n</style>\n</head>\n<body>\n<nav class=\"nav\">\n<div class=\"nav-header\"><div class=\"nav-logo\"><span>🤖</span> AI Hub</div></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">模型</div>\n<div class=\"nav-item active\" data-page=\"chat\"><span class=\"nav-item-icon\">💬</span> 对话</div>\n<div class=\"nav-item\" data-page=\"assistants\"><span class=\"nav-item-icon\">🎭</span> 助手</div>\n<div class=\"nav-item\" data-page=\"providers\"><span class=\"nav-item-icon\">📦</span> 模型服务</div>\n<div class=\"nav-item\" data-page=\"default-model\"><span class=\"nav-item-icon\">🎯</span> 默认模型</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">设置</div>\n<div class=\"nav-item\" data-page=\"general\"><span class=\"nav-item-icon\">⚙️</span> 常规设置</div>\n<div class=\"nav-item\" data-page=\"display\"><span class=\"nav-item-icon\">🖥️</span> 显示设置</div>\n<div class=\"nav-item\" data-page=\"data\"><span class=\"nav-item-icon\">💾</span> 数据设置</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">功能</div>\n<div class=\"nav-item\" data-page=\"mcp\"><span class=\"nav-item-icon\">🔌</span> MCP</div>\n<div class=\"nav-item\" data-page=\"notes\"><span class=\"nav-item-icon\">📝</span> 笔记</div>\n<div class=\"nav-item\" data-page=\"search\"><span class=\"nav-item-icon\">🌐</span> 网络搜索</div>\n<div class=\"nav-item\" data-page=\"memory\"><span class=\"nav-item-icon\">🧠</span> 全局记忆</div>\n<div class=\"nav-item\" data-page=\"api-server\"><span class=\"nav-item-icon\">🖥️</span> API 服务器</div>\n<div class=\"nav-item\" data-page=\"documents\"><span class=\"nav-item-icon\">📄</span> 文档处理</div>\n<div class=\"nav-item\" data-page=\"shortcuts\"><span class=\"nav-item-icon\">⚡</span> 快捷短语</div>\n<div class=\"nav-item\" data-page=\"hotkeys\"><span class=\"nav-item-icon\">⌨️</span> 快捷键</div>\n</div>\n<div class=\"nav-divider\"></div>\n<div class=\"nav-section\">\n<div class=\"nav-section-title\">助手</div>\n<div class=\"nav-item\" data-page=\"quick-assistant\"><span class=\"nav-item-icon\">🚀</span> 快捷助手</div>\n<div class=\"nav-item\" data-page=\"selection-assistant\"><span class=\"nav-item-icon\">✂️</span> 划词助手</div>\n</div>\n<div class=\"nav-bottom\">\n<div class=\"nav-item\" data-page=\"about\"><span class=\"nav-item-icon\">ℹ️</span> 关于我们</div>\n<div class=\"nav-item\" id=\"navUser\" onclick=\"showAuthModal()\"><span class=\"nav-item-icon\">👤</span> <span id=\"navUserName\">登录</span></div>\n</div>\n</nav>\n<div class=\"main\">\n<!-- 对话页 -->\n<div id=\"page-chat\" class=\"page active\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\">\n<h3>对话列表</h3>\n<div style=\"display:flex;gap:4px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"searchChats()\" title=\"搜索\">🔍</button><button class=\"btn btn-primary btn-sm\" onclick=\"newChat()\">+</button></div>\n</div>\n<div style=\"padding:8px\"><input type=\"text\" id=\"chatSearchInput\" placeholder=\"搜索对话...\" style=\"width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;display:none\" oninput=\"filterChats(this.value)\"></div>\n<div class=\"sidebar-list\" id=\"chatList\"></div>\n</div>\n<div class=\"content\">\n<div class=\"content-header\">\n<select id=\"chatAssistant\" onchange=\"onAssistantChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatProvider\" onchange=\"onProviderChange()\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text)\"></select>\n<select id=\"chatModel\" style=\"padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);min-width:150px\"></select>\n<div style=\"margin-left:auto;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"toggleWebSearch()\" id=\"webSearchBtn\" title=\"网络搜索\">🌐</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showChatSettings()\" title=\"设置\">⚙️</button>\n</div>\n</div>\n<div class=\"chat-messages\" id=\"chatMessages\"><div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div></div>\n<div class=\"chat-input-area\">\n<div class=\"chat-toolbar\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadImage()\" title=\"上传图片\">🖼️</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"uploadFile()\" title=\"上传文件\">📎</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"voiceInput()\" title=\"语音输入\">🎤</button>\n<div style=\"flex:1\"></div>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"clearChat()\">🗑️ 清空</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"exportChat()\">📥 导出</button>\n</div>\n<div class=\"chat-input-box\">\n<textarea id=\"chatInput\" placeholder=\"输入消息,Enter 发送,Shift+Enter 换行...\" rows=\"1\" onkeydown=\"handleChatKey(event)\"></textarea>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"stopGeneration()\" id=\"stopBtn\" style=\"display:none\" title=\"停止生成\">⏹️</button>\n<button class=\"btn btn-primary\" onclick=\"sendMessage()\" id=\"sendBtn\">发送</button>\n</div>\n</div>\n</div>\n</div>\n<!-- 助手页 -->\n<div id=\"page-assistants\" class=\"page\">\n<div class=\"sidebar\">\n<div class=\"sidebar-header\"><h3>助手列表</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addAssistant()\">+ 新建</button></div>\n<div class=\"sidebar-list\" id=\"assistantList\"></div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"tabs\"><div class=\"tab active\" onclick=\"switchAssistantTab('info')\">助手</div><div class=\"tab\" onclick=\"switchAssistantTab('settings')\">设置</div></div>\n<div id=\"assistantTabInfo\">\n<div class=\"settings-section\"><h4><span>🎭</span> 助手信息</h4>\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"aName\" placeholder=\"助手名称\"></div>\n<div class=\"form-group\"><label>头像 Emoji</label><input type=\"text\" id=\"aEmoji\" placeholder=\"😀\" maxlength=\"2\"></div>\n<div class=\"form-group\"><label>描述</label><input type=\"text\" id=\"aDesc\" placeholder=\"助手描述\"></div>\n<div class=\"form-group\"><label>系统提示词</label><textarea id=\"aPrompt\" rows=\"6\" placeholder=\"你是一个...\"></textarea></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-primary\" onclick=\"saveAssistant()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteAssistant()\">🗑️ 删除</button></div>\n</div>\n</div>\n<div id=\"assistantTabSettings\" style=\"display:none\">\n<div class=\"settings-section\"><h4><span>⚙️</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度 <small>控制回复的随机性</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('aTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"aTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数 <small>发送给模型的历史消息数</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('aContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"aContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"aStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token 数 <small>限制回复长度</small></div><div class=\"slider-container\"><input type=\"range\" id=\"aMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('aMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"aMaxTokensVal\">2048</span></div></div>\n</div>\n<div class=\"settings-section\"><h4><span>💬</span> 消息设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示提示词</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowPrompt\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">使用衬线字体</div><label class=\"switch\"><input type=\"checkbox\" id=\"aSerifFont\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">思考内容自动折叠</div><label class=\"switch\"><input type=\"checkbox\" id=\"aFoldThinking\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示消息大纲</div><label class=\"switch\"><input type=\"checkbox\" id=\"aShowOutline\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">消息样式</div><select id=\"aMsgStyle\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"simple\">简洁</option><option value=\"bubble\">气泡</option><option value=\"card\">卡片</option></select></div>\n</div>\n</div>\n</div></div></div>\n</div>\n<!-- 模型服务页 -->\n<div id=\"page-providers\" class=\"page\">\n<div class=\"sidebar\"><div class=\"sidebar-header\"><h3>模型服务</h3><button class=\"btn btn-primary btn-sm\" onclick=\"addProvider()\">+ 添加</button></div><div class=\"sidebar-list\" id=\"providerList\"></div></div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\"><h4><span>🔧</span> 服务配置</h4>\n<div class=\"form-group\"><label>服务名称</label><input type=\"text\" id=\"pName\" placeholder=\"OpenAI\"></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"pUrl\" placeholder=\"https://api.openai.com/v1\"></div>\n<div class=\"form-row\"><div class=\"form-group\"><label>API Key</label><input type=\"password\" id=\"pKey\" placeholder=\"sk-xxx\"></div><div class=\"form-group\"><label>类型</label><select id=\"pType\"><option value=\"openai\">OpenAI</option><option value=\"claude\">Claude</option></select></div></div>\n<div style=\"display:flex;gap:12px\"><button class=\"btn btn-ghost\" onclick=\"testProvider()\">🔍 测试</button><button class=\"btn btn-primary\" onclick=\"saveProvider()\">💾 保存</button><button class=\"btn btn-danger\" onclick=\"deleteProvider()\">🗑️ 删除</button></div>\n</div>\n<div class=\"settings-section\"><h4><span>📋</span> 模型列表</h4><div style=\"margin-bottom:12px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"addModel()\">+ 添加</button><button class=\"btn btn-ghost btn-sm\" onclick=\"fetchModels()\">🔄 获取</button></div><div id=\"modelList\"></div></div>\n</div></div></div>\n</div>\n<!-- 默认模型页 -->\n<div id=\"page-default-model\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎯</span> 默认模型</h4>\n<p style=\"color:var(--text2);margin-bottom:20px\">设置不同场景使用的默认模型</p>\n<div class=\"form-group\"><label>💬 对话模型<br><small style=\"color:var(--text2)\">用于日常对话的默认模型</small></label><div class=\"form-row\"><select id=\"defaultChatProvider\" onchange=\"onDefaultProviderChange('chat')\" style=\"flex:1\"></select><select id=\"defaultChatModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🌐 翻译模型<br><small style=\"color:var(--text2)\">用于文本翻译的默认模型</small></label><div class=\"form-row\"><select id=\"defaultTranslateProvider\" onchange=\"onDefaultProviderChange('translate')\" style=\"flex:1\"></select><select id=\"defaultTranslateModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>📝 摘要模型<br><small style=\"color:var(--text2)\">用于内容摘要的默认模型</small></label><div class=\"form-row\"><select id=\"defaultSummaryProvider\" onchange=\"onDefaultProviderChange('summary')\" style=\"flex:1\"></select><select id=\"defaultSummaryModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>💻 代码模型<br><small style=\"color:var(--text2)\">用于代码生成和分析的默认模型</small></label><div class=\"form-row\"><select id=\"defaultCodeProvider\" onchange=\"onDefaultProviderChange('code')\" style=\"flex:1\"></select><select id=\"defaultCodeModel\" style=\"flex:1\"></select></div></div>\n<div class=\"form-group\"><label>🚀 快捷助手模型<br><small style=\"color:var(--text2)\">快捷助手使用的默认模型</small></label><div class=\"form-row\"><select id=\"defaultQuickProvider\" onchange=\"onDefaultProviderChange('quick')\" style=\"flex:1\"></select><select id=\"defaultQuickModel\" style=\"flex:1\"></select></div></div>\n<button class=\"btn btn-primary\" onclick=\"saveDefaultModels()\">💾 保存设置</button>\n</div>\n</div></div></div></div>\n<!-- 常规设置页 -->\n<div id=\"page-general\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">语言</div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:16px\">🇨🇳</span><select id=\"appLanguage\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zh-CN\">中文</option><option value=\"en\">English</option><option value=\"ja\">日本語</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代理模式</div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统代理</option><option>自定义代理</option><option>不使用代理</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">拼写检查</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">禁用硬件加速</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔔</span> 通知设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">桌子消息 ⓘ</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">音效</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识库</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚀</span> 启动</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">开机启动</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📌</span> 托盘</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示托盘图标</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">关闭时最小化到托盘</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔒</span> 隐私设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">匿名发送错误报告和数据统计</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 开发者模式</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用开发者模式<br><small style=\"color:var(--text2)\">启用后可以使用开发者工具和调试功能</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n</div></div></div></div>\n<!-- 显示设置页 -->\n<div id=\"page-display\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🎨</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\" onclick=\"setTheme('light')\">☀️ 浅色</button><button class=\"theme-btn active\" onclick=\"setTheme('dark')\">🌙 深色</button><button class=\"theme-btn\" onclick=\"setTheme('auto')\">💻 系统</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">主题颜色</div><div style=\"display:flex;gap:8px;align-items:center\"><div class=\"color-picker\" style=\"background:#22c55e\" onclick=\"setAccent('#22c55e')\"></div><div class=\"color-picker\" style=\"background:#ef4444\" onclick=\"setAccent('#ef4444')\"></div><div class=\"color-picker\" style=\"background:#06b6d4\" onclick=\"setAccent('#06b6d4')\"></div><div class=\"color-picker\" style=\"background:#3b82f6\" onclick=\"setAccent('#3b82f6')\"></div><div class=\"color-picker active\" style=\"background:#6366f1\" onclick=\"setAccent('#6366f1')\"></div><div class=\"color-picker\" style=\"background:#8b5cf6\" onclick=\"setAccent('#8b5cf6')\"></div><div class=\"color-picker\" style=\"background:#ec4899\" onclick=\"setAccent('#ec4899')\"></div><div class=\"color-picker\" style=\"background:#f59e0b\" onclick=\"setAccent('#f59e0b')\"></div><div class=\"color-picker\" style=\"background:#14b8a6\" onclick=\"setAccent('#14b8a6')\"></div><input type=\"text\" value=\"#00B96B\" style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>📍</span> 导航栏设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导航栏位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn active\">左侧</button><button class=\"theme-btn\">顶部</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔍</span> 缩放设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩放</div><div style=\"display:flex;align-items:center;gap:12px\"><button class=\"btn btn-ghost btn-sm\">−</button><span>100%</span><button class=\"btn btn-ghost btn-sm\">+</button><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><h4 style=\"margin:0\"><span>🔤</span> 字体设置</h4><span class=\"tag tag-primary\" style=\"font-size:10px\">New</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">全局字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>微软雅黑</option><option>思源黑体</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码字体</div><div style=\"display:flex;align-items:center;gap:8px\"><select style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>默认</option><option>Consolas</option><option>Fira Code</option></select><button class=\"btn btn-ghost btn-sm\">↺</button></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💬</span> 话题设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">话题位置</div><div style=\"display:flex;gap:8px\"><button class=\"theme-btn\">左侧</button><button class=\"theme-btn active\">右侧</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动切换到话题</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示话题时间</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">固定话题置顶</div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🤖</span> 助手设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型图标行为</div><div style=\"display:flex;gap:8px\"><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>Emoji 字体</option><option>系统字体</option></select></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">代码块显示行号<br><small style=\"color:var(--text2)\">在代码块中显示行号</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showLineNumbers\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 界面布局</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">侧边栏宽度<br><small style=\"color:var(--text2)\">调整左侧导航栏宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"180\" max=\"300\" value=\"220\" id=\"sidebarWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">220px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话列表宽度<br><small style=\"color:var(--text2)\">调整对话列表区域宽度</small></div><div class=\"slider-container\"><input type=\"range\" min=\"200\" max=\"400\" value=\"280\" id=\"chatListWidth\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">280px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示对话导航按钮<br><small style=\"color:var(--text2)\">在对话区域显示上下导航按钮</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"showNavButtons\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<button class=\"btn btn-primary\" onclick=\"saveDisplaySettings()\">💾 保存设置</button>\n<button class=\"btn btn-ghost\" onclick=\"resetDisplaySettings()\" style=\"margin-left:12px\">重置为默认</button>\n</div>\n</div></div></div></div>\n<!-- 数据设置页 -->\n<div id=\"page-data\" class=\"page\">\n<div class=\"settings-sidebar\">\n<div class=\"settings-sidebar-title\">数据和备份设置</div>\n<div class=\"settings-sidebar-item active\" onclick=\"switchDataTab('directory')\">📁 数据目录</div>\n<div class=\"settings-sidebar-title\">云备份设置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('local')\">💾 本地备份</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('webdav')\">☁️ WebDAV</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('icloud')\">🍎 坚果云配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('s3')\">📦 S3 兼容存储</div>\n<div class=\"settings-sidebar-title\">快捷按钮</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('export')\">📤 以对话单位导出</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('markdown')\">📝 Markdown 导出</div>\n<div class=\"settings-sidebar-title\">第三方同步</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('notion')\">📓 Notion 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('yuque')\">📖 语雀配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('joplin')\">🎵 Joplin 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('obsidian')\">💎 Obsidian 配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('siyuan')\">📔 思源笔记配置</div>\n<div class=\"settings-sidebar-item\" onclick=\"switchDataTab('zhishiku')\">💡 智能体配置</div>\n</div>\n<div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>💾</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">数据备份与恢复</div><div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost\" onclick=\"exportAllData()\">备份</button><button class=\"btn btn-ghost\" onclick=\"importData()\">恢复</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">简易备份<br><small style=\"color:var(--text2)\">备份包括已备份的数据,如对话记录/模型人工上架和配置,减少空间占用,快速备份恢复</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">导出至手机</div><button class=\"btn btn-ghost btn-sm\">📱 局域网传输</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据目录</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用数据</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">修改目录</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">应用 Logs</div><div style=\"display:flex;gap:8px;align-items:center\"><input type=\"text\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\logs\" readonly style=\"width:350px;background:var(--bg3);font-size:12px\"><button class=\"btn btn-ghost btn-sm\">打开日志</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">知识小文件</div><button class=\"btn btn-ghost btn-sm\">📁 相关文件</button></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">清除缓存 <small style=\"color:var(--text2)\">(5.2MB)</small></div><button class=\"btn btn-ghost btn-sm\">清除缓存</button></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚠️</span> 重置数据</h4>\n<button class=\"btn btn-danger\" onclick=\"clearAllData()\">⚠️ 重置数据</button>\n</div>\n<div class=\"settings-section\">\n<h4><span>📊</span> 存储统计</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">对话数量</div><span id=\"statChats\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">助手数量</div><span id=\"statAssistants\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷短语</div><span id=\"statShortcuts\">0</span></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">本地存储使用</div><span id=\"statStorage\">0 KB</span></div>\n</div>\n</div></div></div></div>\n<!-- MCP页 -->\n<div id=\"page-mcp\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"text-align:center;padding:40px\">\n<div style=\"font-size:48px;margin-bottom:16px;opacity:0.5\">🔌</div>\n<p style=\"color:var(--text2)\">未启用服务器</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>🌐</span> 更多 MCP</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px\">\n<div class=\"mcp-market-card\" onclick=\"window.open('https://bigmodel.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔵</span><div><div style=\"font-weight:500\">BigModel MCP Market</div><div style=\"font-size:12px;color:var(--text2)\">机器MCP,应有尽有</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://modelscope.cn/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟢</span><div><div style=\"font-weight:500\">modelscope.cn</div><div style=\"font-size:12px;color:var(--text2)\">魔搭社区 MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.higress.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟣</span><div><div style=\"font-weight:500\">mcp.higress.ai</div><div style=\"font-size:12px;color:var(--text2)\">Higress MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.so','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">Ⓜ️</span><div><div style=\"font-weight:500\">mcp.so</div><div style=\"font-size:12px;color:var(--text2)\">MCP 服务发现平台</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://smithery.ai','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🔨</span><div><div style=\"font-weight:500\">smithery.ai</div><div style=\"font-size:12px;color:var(--text2)\">Smithery MCP 工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://glama.ai/mcp','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">🟡</span><div><div style=\"font-weight:500\">glama.ai</div><div style=\"font-size:12px;color:var(--text2)\">Glama MCP 服务器目录</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://pulsemcp.com','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px;color:#ec4899\">🅿️</span><div><div style=\"font-weight:500\">pulsemcp.com</div><div style=\"font-size:12px;color:var(--text2)\">Pulse MCP 服务器</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://mcp.composio.dev','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⚡</span><div><div style=\"font-weight:500\">mcp.composio.dev</div><div style=\"font-size:12px;color:var(--text2)\">Composio MCP 开发工具</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/modelcontextprotocol/servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">📋</span><div><div style=\"font-weight:500\">Model Context Protocol Servers</div><div style=\"font-size:12px;color:var(--text2)\">官方 MCP 服务器仓库</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n<div class=\"mcp-market-card\" onclick=\"window.open('https://github.com/punkpeye/awesome-mcp-servers','_blank')\"><div style=\"display:flex;align-items:center;gap:10px\"><span style=\"font-size:20px\">⭐</span><div><div style=\"font-weight:500\">Awesome MCP Servers</div><div style=\"font-size:12px;color:var(--text2)\">精选 MCP 服务器列表</div></div></div><span style=\"color:var(--text2)\">↗</span></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🛠️</span> 内置服务器</h4>\n<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px\">\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/mcp-auto-install</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">自动安装 MCP 服务(测试版)</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/memory</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让大模型记住你的对话上下文,包含全局记忆功能,保存 AI 助手的记忆,让对话更连贯</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/sequentialthinking</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让 MCP 服务器深度思考,支持/追溯问题来源并进行分析,让 AI 更有逻辑性地回答问题</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/brave-search</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">使用 Brave 搜索 API 进行 MCP 服务器搜索文档,支持搜索网页和新闻,需要配置 BRAVE_API_KEY 环境变量</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/fetch</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">用于获取 URL 网页内容的 MCP 服务器</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/filesystem</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">让模型文件系统操作的模型上下文协议(MCP)的 Node.js 服务器,支持读取、写入和删除文件</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/dify-knowledge</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">Dify 的 MCP 服务器实现,使用了一个简单的 API 来检索 Dify 知识库,需要配置 Dify Key</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--warning);color:#fff\">需要配置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/python</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">在安全的沙箱环境中执行 Python 代码,使用 Pyodide 运行 Python,支持人工审核和代码执行</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span></div></div>\n<div class=\"mcp-server-card\"><div class=\"mcp-server-header\"><span style=\"font-weight:500\">@cherry/didi-mcp</span><span class=\"mcp-add-btn\">+</span></div><div class=\"mcp-server-desc\">一个生成了滴滴 MCP 服务器实现,帮助用户打车服务包括路线查询、价格预估、订单管理和司机调度,仅支持中国...</div><div class=\"mcp-server-tags\"><span class=\"tag\" style=\"background:var(--accent);color:#fff\">内置</span><span class=\"tag\" style=\"background:var(--error);color:#fff\">实验性功能</span></div></div>\n</div>\n</div>\n</div></div></div></div>\n<!-- 笔记页 -->\n<div id=\"page-notes\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>📁</span> 数据设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">当前工作目录</div></div>\n<div style=\"display:flex;gap:8px;margin-bottom:16px\">\n<input type=\"text\" id=\"notesWorkDir\" value=\"C:\\Users\\legion\\AppData\\Roaming\\AIHub\\Data\\Notes\" readonly style=\"flex:1;background:var(--bg3)\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"selectNotesDir()\">📁 选择</button>\n</div>\n<div style=\"display:flex;gap:8px;margin-bottom:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"applyNotesDir()\">🔄 应用</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"resetNotesDir()\">重置为默认</button>\n</div>\n<p style=\"font-size:12px;color:var(--text2)\">工作目录保存笔记文件位置,更换工作目录不会移动原有文件,请手动迁移文件。</p>\n</div>\n<div class=\"settings-section\">\n<h4><span>✏️</span> 编辑器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认视图<br><small style=\"color:var(--text2)\">新建笔记时的视图模式</small></div><select id=\"noteDefaultView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"edit\">编辑模式</option><option value=\"preview\">预览模式</option><option value=\"split\">分屏模式</option></select></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">默认编辑视图<br><small style=\"color:var(--text2)\">在编辑模式下,新建笔记时采用的编辑模式</small></div><select id=\"noteEditView\" style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"source\">源码模式</option><option value=\"wysiwyg\">实时预览</option></select></small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>实时预览</option><option>源码模式</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🖥️</span> 显示设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">缩减行宽<br><small style=\"color:var(--text2)\">开启后将限制每行字数,使段落更易阅读</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">字体大小<br><small style=\"color:var(--text2)\">调整字体大小以获得更好的阅读体验 (10-30px)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"10\" max=\"30\" value=\"16\" oninput=\"this.nextElementSibling.textContent=this.value+'px'\"><span class=\"slider-value\">16px</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">显示目录大纲<br><small style=\"color:var(--text2)\">显示目录大纲导航栏,方便文档导航</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n</div>\n<!-- 简化版笔记区域,避免渲染空节点导致的 JS 报错 -->\n<div style=\"margin-top:16px;display:grid;grid-template-columns:240px 1fr;gap:12px\">\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;min-height:200px;padding:12px\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px\">\n <div style=\"font-weight:600\">笔记列表</div>\n <button class=\"btn btn-ghost btn-sm\" onclick=\"newNote()\">+ 新建</button>\n </div>\n <div id=\"noteList\" style=\"display:flex;flex-direction:column;gap:6px\"></div>\n </div>\n <div style=\"background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:12px;min-height:200px;display:flex;flex-direction:column;gap:8px\">\n <input id=\"noteTitle\" placeholder=\"标题\" style=\"padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text)\">\n <textarea id=\"noteContent\" placeholder=\"内容\" style=\"flex:1;min-height:180px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text);resize:vertical\"></textarea>\n <div style=\"display:flex;gap:8px;justify-content:flex-end\">\n <button class=\"btn btn-ghost btn-sm\" onclick=\"deleteNote()\">删除</button>\n <button class=\"btn btn-primary btn-sm\" onclick=\"saveNote()\">保存</button>\n </div>\n </div>\n</div></div></div></div>\n<!-- 网络搜索页 -->\n<div id=\"page-search\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🌐</span> 网络搜索</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索服务商</div><select id=\"searchProvider\" onchange=\"onSearchProviderChange()\" style=\"width:180px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option value=\"zhipu\">Zhipu (API 密钥)</option><option value=\"searxng\">SearXNG</option><option value=\"tavily\">Tavily</option><option value=\"exa\">Exa</option></select></div>\n</div>\n<div class=\"settings-section\" id=\"searchZhipuSection\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--accent)\">●</span><span>Zhipu</span><a href=\"https://open.bigmodel.cn\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"zhipuSearchKey\" placeholder=\"输入 Zhipu API 密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\" onclick=\"togglePassword('zhipuSearchKey')\">👁️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"testSearchKey()\">检测</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://open.bigmodel.cn/api/paas/v4/web_search\" readonly style=\"background:var(--bg3)\"></div>\n</div>\n<div class=\"settings-section\" id=\"searchSearxngSection\" style=\"display:none\">\n<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:16px\"><span style=\"color:var(--success)\">●</span><span>SearXNG</span><a href=\"https://searx.space\" target=\"_blank\" style=\"color:var(--text2);font-size:12px\">↗</a></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" id=\"searxngUrl\" value=\"https://search.inetol.net\" placeholder=\"https://search.inetol.net\"></div>\n<div class=\"form-group\"><label>API 密钥</label><input type=\"password\" id=\"searxngKey\" placeholder=\"可选,某些实例需要\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 常规设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索已启用<br><small style=\"color:var(--text2)\">启用后,AI 可以搜索互联网获取最新信息</small></div><label class=\"switch\"><input type=\"checkbox\" id=\"searchEnabled\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">搜索结果个数<br><small style=\"color:var(--text2)\">每次搜索返回的结果数量 (1-100)</small></div><div class=\"slider-container\"><input type=\"range\" min=\"1\" max=\"100\" value=\"5\" id=\"searchResultCount\" oninput=\"this.nextElementSibling.textContent=this.value\"><span class=\"slider-value\">5</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📦</span> 搜索结果压缩</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">压缩方法<br><small style=\"color:var(--text2)\">对搜索结果进行压缩以节省 Token</small></div><select style=\"width:120px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>不压缩</option><option>简单压缩</option><option>AI 压缩</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🚫</span> 黑名单</h4>\n<div class=\"form-group\"><label>在搜索结果中不会出现以下网站的结果<br><small style=\"color:var(--text2)\">请按以下格式添加(每行一个)</small></label><textarea rows=\"4\" id=\"searchBlacklist\" placeholder=\"完整域名: *.example.com/*&#10;正则表达式: /.*example\\.net\\.org/\"></textarea></div>\n<button class=\"btn btn-primary\" onclick=\"saveSearchSettings()\">保存</button>\n</div>\n</div></div></div></div>\n<!-- 全局记忆页 -->\n<div id=\"page-memory\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div style=\"display:flex;align-items:center;gap:12px\"><h4 style=\"margin:0\"><span>🧠</span> 全局记忆</h4><span class=\"tag tag-primary\">Beta</span></div>\n<div style=\"display:flex;align-items:center;gap:12px\"><label class=\"switch\"><input type=\"checkbox\" id=\"memoryEnabled\" checked><span class=\"switch-slider\"></span></label><button class=\"btn btn-ghost btn-sm\">⚙️</button></div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>👤</span> 用户管理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户 ID<br><small style=\"color:var(--text2)\">0 条记忆</small></div><div style=\"display:flex;align-items:center;gap:8px\"><span style=\"display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--accent);color:#fff;border-radius:6px;font-size:13px\">👤 默认用户</span><select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select><button class=\"btn btn-ghost btn-sm\">👤</button></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">用户<br><small style=\"color:var(--text2)\">临时</small></div><span class=\"tag\" style=\"background:var(--success);color:#fff\">0</span></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>📚</span> 全局记忆</h4>\n<div style=\"display:flex;gap:8px;align-items:center\">\n<input type=\"text\" placeholder=\"搜索记忆...\" style=\"width:150px;padding:6px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px\">\n<button class=\"btn btn-primary btn-sm\" onclick=\"showAddMemoryModal()\">+ 添加记忆</button>\n<button class=\"btn btn-ghost btn-sm\">≡ 更多</button>\n</div>\n</div>\n<div id=\"memoryList\"></div>\n</div>\n</div></div></div></div>\n<!-- API服务器页 -->\n<div id=\"page-api-server\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<div><h4 style=\"margin:0\"><span>🖥️</span> API 服务器</h4><p style=\"color:var(--text2);font-size:13px;margin-top:4px\">通过 OpenAI 兼容的 HTTP API 暴露 AI Hub 的 AI 功能</p></div>\n<button class=\"btn btn-primary\" onclick=\"window.open('/docs','_blank')\">📄 API 文档</button>\n</div>\n<div class=\"card\" style=\"background:var(--bg)\">\n<div style=\"display:flex;justify-content:space-between;align-items:center\">\n<div style=\"display:flex;align-items:center;gap:8px\"><span style=\"width:10px;height:10px;background:var(--success);border-radius:50%;animation:pulse 2s infinite\"></span><span style=\"color:var(--success);font-weight:500\">运行中</span><a href=\"http://localhost:8000\" target=\"_blank\" style=\"color:var(--text2);font-size:13px\">http://localhost:8000</a></div>\n<div style=\"display:flex;gap:8px\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText('http://localhost:8000')\">📋</button><button class=\"btn btn-ghost btn-sm\">🗑️</button></div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔑</span> API 密钥</h4>\n<p style=\"color:var(--text2);font-size:13px;margin-bottom:16px\">用于 API 认证的令牌</p>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"text\" id=\"apiServerKey\" value=\"cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"flex:1;background:var(--bg3);font-family:monospace\"><button class=\"btn btn-ghost btn-sm\" onclick=\"copyText($('apiServerKey').value)\">📋</button></div></div>\n<div class=\"form-group\"><label>授权标头</label><input type=\"text\" value=\"Authorization: Bearer cs-sk-e6a3d630-0f63-40f8-95f3-d6d6bc8a8424\" readonly style=\"background:var(--bg3);font-family:monospace;font-size:12px\"></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>⚙️</span> 服务器设置</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用 API 服务器</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">端口号</div><input type=\"number\" value=\"8000\" style=\"width:100px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">允许跨域请求 (CORS)</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📖</span> 使用说明</h4>\n<div class=\"card\" style=\"background:var(--bg)\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">Base URL:</p><code style=\"display:block;padding:12px;background:var(--bg3);border-radius:8px;font-family:monospace\">http://localhost:8000/v1</code></div>\n<div class=\"card\" style=\"background:var(--bg);margin-top:12px\"><p style=\"font-size:13px;color:var(--text2);margin-bottom:8px\">示例请求:</p><pre style=\"padding:12px;background:var(--bg3);border-radius:8px;font-size:12px;overflow-x:auto;margin:0\"><code>curl http://localhost:8000/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"model\":\"gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'</code></pre></div>\n</div>\n</div></div></div></div>\n<!-- 文档处理页 -->\n<div id=\"page-documents\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🔍</span> OCR 服务</h4>\n<div class=\"tabs\" style=\"margin-bottom:16px\"><div class=\"tab active\">📄 图片</div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">OCR 服务提供商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>系统 OCR</option><option>百度 OCR</option><option>腾讯 OCR</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>💻</span> 系统 OCR</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">支持的语言</div><div style=\"display:flex;gap:8px\"><span class=\"tag\">🇨🇳 中文</span><span class=\"tag\">🇺🇸 英文</span></div></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📄</span> 文档处理</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">文档处理服务商</div><select style=\"width:150px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)\"><option>MinerU</option><option>本地解析</option></select></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔗</span> MinerU</h4>\n<div class=\"form-group\"><label>API 密钥</label><div style=\"display:flex;gap:8px\"><input type=\"password\" id=\"mineruKey\" placeholder=\"MinerU 提供每日 500 页的免费额度,您不需要输入密钥\" style=\"flex:1\"><button class=\"btn btn-ghost btn-sm\">👁️</button></div><a href=\"#\" style=\"font-size:12px;color:var(--accent)\">点击这里获取密钥</a><span style=\"font-size:12px;color:var(--text2);margin-left:auto\">多个密钥请用逗号分隔</span></div>\n<div class=\"form-group\"><label>API 地址</label><input type=\"text\" value=\"https://mineru.net\" readonly></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📁</span> 上传文档</h4>\n<div style=\"border:2px dashed var(--border);border-radius:12px;padding:40px;text-align:center;cursor:pointer\" onclick=\"document.getElementById('fileInput').click()\"><span style=\"font-size:48px;display:block;margin-bottom:12px\">📁</span><p style=\"color:var(--text2)\">点击上传文件</p><p style=\"color:var(--text2);font-size:12px;margin-top:8px\">支持 PDF, DOCX, TXT, MD 等格式</p></div>\n<input type=\"file\" id=\"fileInput\" style=\"display:none\" onchange=\"handleFileUpload(event)\">\n</div>\n<div class=\"settings-section\" id=\"docResult\" style=\"display:none\"><h4><span>📝</span> 内容</h4><div id=\"docContent\" style=\"background:var(--bg);padding:16px;border-radius:8px;max-height:300px;overflow-y:auto;white-space:pre-wrap\"></div><div style=\"margin-top:16px\"><button class=\"btn btn-primary\" onclick=\"summarizeDoc()\">📊 摘要</button><button class=\"btn btn-ghost\" onclick=\"askAboutDoc()\">💬 提问</button></div></div>\n</div></div></div></div>\n<!-- 快捷短语页 -->\n<div id=\"page-shortcuts\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 快捷短语</h4>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"showAddShortcutModal()\">+</button>\n</div>\n<div id=\"shortcutList\" style=\"min-height:200px\"></div>\n</div>\n</div></div></div></div>\n<!-- 快捷键页 -->\n<div id=\"page-hotkeys\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\" style=\"padding:16px\">\n<h4 style=\"margin-bottom:16px\"><span>⌨️</span> 快捷键</h4>\n<div class=\"hotkey-row\"><span>放大界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + =</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>缩小界面</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + -</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重置缩放</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + 0</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>打开设置</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ,</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>显示/隐藏应用</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>快捷助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>开关划词助手</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>划词助手:取词</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">按下快捷键</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>退出全屏</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Escape</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>新建话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + N</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>重命名话题</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + T</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换助手显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + [</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>切换话题显示</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + ]</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>复制上一条消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + C</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n<div class=\"hotkey-row\"><span>编辑最后一条用户消息</span><div class=\"hotkey-right\"><span class=\"hotkey-key\">Ctrl + Shift + E</span><span class=\"hotkey-info\">ℹ️</span><span class=\"hotkey-lock\">🔒</span><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div></div>\n</div>\n</div></div></div></div>\n<!-- 快捷助手页 -->\n<div id=\"page-quick-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<h4><span>🚀</span> 快捷助手</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用快捷助手</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">点击托盘图标启动</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启动时读取剪贴板</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">快捷助手模型</div>\n<div style=\"display:flex;align-items:center;gap:12px\">\n<span style=\"display:flex;align-items:center;gap:6px\">😀 默认助手</span>\n<select style=\"width:80px;padding:6px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px\"><option>默认</option></select>\n<div style=\"display:flex;gap:4px\">\n<button class=\"btn btn-primary btn-sm\">使用助手</button>\n<button class=\"btn btn-ghost btn-sm\">默认模型</button>\n</div>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;margin:16px 0;justify-content:center\">\n<span style=\"font-size:20px;cursor:pointer\" title=\"Suno\">🎵</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"中文\">中</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"画图\">🎨</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"邮件\">📧</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"Twitter\">🐦</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"代码\">💻</span>\n<span style=\"font-size:20px;cursor:pointer\" title=\"更多\">😀</span>\n</div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:12px;padding:12px;background:var(--bg);border-radius:10px;margin-bottom:16px\">\n<span style=\"font-size:24px\">😀</span>\n<span style=\"color:var(--text2)\">询问 默认助手 获取帮助...</span>\n</div>\n<div style=\"background:var(--bg);border-radius:10px;padding:12px;margin-bottom:12px\">\n<div style=\"display:flex;align-items:center;gap:8px;color:var(--text2);font-size:14px\">\n<span>💬</span> 回答此问题\n<span style=\"margin-left:auto\">↵</span>\n</div>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">文本翻译</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">📄</div><div class=\"list-item-content\"><div class=\"list-item-title\">内容总结</div></div></div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">💡</div><div class=\"list-item-content\"><div class=\"list-item-title\">解释说明</div></div></div>\n</div>\n<div style=\"text-align:center;padding:12px;color:var(--text2);font-size:12px\">⌘ 按 ESC 关闭</div>\n</div></div></div></div>\n<!-- 划词助手页 -->\n<div id=\"page-selection-assistant\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:20px\">\n<h4 style=\"margin:0\"><span>✂️</span> 划词助手</h4>\n<a href=\"#\" style=\"color:var(--accent);font-size:13px\">FAQ & 反馈</a>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">启用</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🔧</span> 工具栏</h4>\n<div class=\"setting-row\">\n<div class=\"setting-row-label\">取词方式<br><small style=\"color:var(--text2)\">划词后,触发划词助手的方式</small></div>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-primary btn-sm\">划词</button>\n<button class=\"btn btn-ghost btn-sm\">Ctrl 键</button>\n<button class=\"btn btn-ghost btn-sm\">快捷键</button>\n</div>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">紧凑模式<br><small style=\"color:var(--text2)\">紧凑模式下,只显示图标,不显示文字</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>🪟</span> 功能窗口</h4>\n<div class=\"setting-row\"><div class=\"setting-row-label\">跟随工具栏<br><small style=\"color:var(--text2)\">窗口位置跟随工具栏显示,让回答内容离划词位置更近</small></div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">钉住人小<br><small style=\"color:var(--text2)\">钉住后,窗口会保持上次调整的大小显示</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动关闭<br><small style=\"color:var(--text2)\">当鼠标不在窗口区域时关闭,将自动关闭窗口</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动朗读<br><small style=\"color:var(--text2)\">默认将朗读上次打开的翻译</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">透明度<br><small style=\"color:var(--text2)\">设置窗口透明度,100% 为完全不透明</small></div><div class=\"slider-container\"><span class=\"slider-value\">100%</span><input type=\"range\" min=\"50\" max=\"100\" value=\"100\" style=\"width:150px\"></div></div>\n</div>\n<div class=\"settings-section\">\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px\">\n<h4 style=\"margin:0\"><span>⚡</span> 功能</h4>\n<div style=\"display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\">重置</button>\n<button class=\"btn btn-primary btn-sm\">+ 自定义功能</button>\n</div>\n</div>\n<div style=\"display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding:12px;background:var(--bg);border-radius:8px\">\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--error);color:#fff;border-radius:6px;font-size:13px\">🚫 禁用</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🌐 翻译</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📖 解释</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📊 总结</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">🔍 搜索</span>\n<span style=\"display:flex;align-items:center;gap:4px;padding:6px 12px;background:var(--bg3);border-radius:6px;font-size:13px\">📋 复制</span>\n</div>\n<div class=\"list-item\" style=\"cursor:pointer\"><div class=\"list-item-icon\" style=\"background:transparent;font-size:20px\">🌐</div><div class=\"list-item-content\"><div class=\"list-item-title\">翻译</div></div></div>\n</div>\n</div></div></div></div>\n<!-- 关于我们页 -->\n<div id=\"page-about\" class=\"page\"><div class=\"content\"><div class=\"content-body\"><div class=\"settings-panel\">\n<div class=\"settings-section\">\n<div style=\"display:flex;align-items:center;gap:20px;margin-bottom:24px\">\n<div style=\"width:80px;height:80px;background:linear-gradient(135deg,#6366f1,#ec4899);border-radius:20px;display:flex;align-items:center;justify-content:center;font-size:40px\">🤖</div>\n<div><h2 style=\"font-size:24px;margin-bottom:4px\">AI Hub</h2><p style=\"color:var(--text2)\">一款为创造者而生的 AI 助手</p><span class=\"tag tag-primary\" style=\"margin-top:8px;display:inline-block\">v1.7.2</span></div>\n<button class=\"btn btn-ghost\" style=\"margin-left:auto\" onclick=\"checkUpdate()\">立即更新</button>\n</div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">自动更新</div><label class=\"switch\"><input type=\"checkbox\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">测试计划 <small>获取最新测试版本</small></div><label class=\"switch\"><input type=\"checkbox\"><span class=\"switch-slider\"></span></label></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📋</span> 发现新版本 1.7.2</h4>\n<div class=\"changelog\">\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.2 - 稳定性与体验提升<span class=\"changelog-date\">2024-12-10</span></div>\n<div class=\"changelog-content\">本次更新专注于稳定性改进,同时修复用户体验问题。\n<ul>\n<li>🎨 <b>功能改进</b></li>\n<li>增强聊天对话框确认删除状态管理</li>\n<li>优化因只言左键右键对齐体验</li>\n<li>改进温度和 top_p 参数处理逻辑</li>\n<li>支持用户自定义 OpenAI API 认证头</li>\n<li>翻译功能窗口支持义格义格义件</li>\n</ul>\n<ul>\n<li>🤖 <b>AI 与模型</b></li>\n<li>为 Gemini 3 Pro Image 添加图片式请求 token 支持</li>\n<li>更新 DeepSeek 模型以适配 DeepSeek v3.2</li>\n<li>更新 AiOnly 默认模型</li>\n<li>更新 AI 模型配置至最新版本</li>\n</ul>\n<ul>\n<li>♿ <b>无障碍支持</b></li>\n<li>改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性</li>\n<li>新增阴影按钮边框与检查支持</li>\n</ul>\n<ul>\n<li>🐛 <b>问题修复</b></li>\n<li>修复快捷助手无法注册快捷键的问题</li>\n<li>修复多文件流消息时 UI 活动问题(通过批处理优化)</li>\n<li>修复翻译结果用到 textBlock 主题主题的问题</li>\n</ul>\n</div>\n</div>\n<div class=\"changelog-item\">\n<div class=\"changelog-version\">AI Hub 1.7.1<span class=\"changelog-date\">2024-12-05</span></div>\n<div class=\"changelog-content\">\n<ul>\n<li>新增多模型同时回答功能</li>\n<li>优化流式输出性能</li>\n<li>修复若干已知问题</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📞</span> 联系我们</h4>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('mailto:support@aihub.com')\"><div class=\"list-item-icon\">📧</div><div class=\"list-item-content\"><div class=\"list-item-title\">邮箱</div><div class=\"list-item-desc\">support@aihub.com</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://github.com/aihub','_blank')\"><div class=\"list-item-icon\">🐙</div><div class=\"list-item-content\"><div class=\"list-item-title\">GitHub</div><div class=\"list-item-desc\">github.com/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://discord.gg/aihub','_blank')\"><div class=\"list-item-icon\">💬</div><div class=\"list-item-content\"><div class=\"list-item-title\">Discord</div><div class=\"list-item-desc\">discord.gg/aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n<div class=\"list-item\" style=\"cursor:pointer\" onclick=\"window.open('https://twitter.com/aihub','_blank')\"><div class=\"list-item-icon\">🐦</div><div class=\"list-item-content\"><div class=\"list-item-title\">Twitter</div><div class=\"list-item-desc\">@aihub</div></div><span style=\"color:var(--accent)\">↗</span></div>\n</div>\n<div class=\"settings-section\">\n<h4><span>📜</span> 开源许可</h4>\n<p style=\"color:var(--text2);font-size:13px;line-height:1.8\">AI Hub 基于 MIT 许可证开源。感谢所有贡献者和开源社区的支持。</p>\n<div style=\"margin-top:16px;display:flex;gap:8px\">\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/LICENSE','_blank')\">查看许可证</button>\n<button class=\"btn btn-ghost btn-sm\" onclick=\"window.open('https://github.com/aihub/CONTRIBUTORS','_blank')\">贡献者名单</button>\n</div>\n</div>\n</div></div></div></div>\n</div>\n<!-- 模态框 -->\n<div class=\"modal\" id=\"authModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3 id=\"authTitle\">登录</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('authModal')\">✕</button></div><div class=\"modal-body\"><div class=\"form-group\"><label>用户名</label><input type=\"text\" id=\"authUsername\" placeholder=\"用户名\"></div><div class=\"form-group\"><label>密码</label><input type=\"password\" id=\"authPassword\" placeholder=\"密码\"></div><div class=\"form-group\" id=\"authEmailGroup\" style=\"display:none\"><label>邮箱</label><input type=\"email\" id=\"authEmail\" placeholder=\"邮箱\"></div><button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"submitAuth()\" id=\"authSubmit\">登录</button><p style=\"text-align:center;margin-top:16px;font-size:14px;color:var(--text2)\" id=\"authSwitch\">没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a></p></div></div></div>\n<div class=\"modal\" id=\"pricingModal\"><div class=\"modal-content\" style=\"max-width:800px\"><div class=\"modal-header\"><h3>选择套餐</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('pricingModal')\">✕</button></div><div class=\"modal-body\"><div class=\"price-cards\" id=\"priceCards\"></div></div></div></div>\n<div class=\"modal\" id=\"paymentModal\"><div class=\"modal-content\" style=\"max-width:400px\"><div class=\"modal-header\"><h3>支付</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('paymentModal')\">✕</button></div><div class=\"modal-body\" style=\"text-align:center\"><div id=\"paymentInfo\"></div><div style=\"margin:24px 0;padding:24px;background:var(--bg);border-radius:12px\"><p style=\"color:var(--text2);margin-bottom:12px\">扫码支付</p><div style=\"width:150px;height:150px;background:var(--bg3);margin:0 auto;border-radius:8px;display:flex;align-items:center;justify-content:center\"><span style=\"font-size:48px\">📱</span></div></div><button class=\"btn btn-success\" style=\"width:100%\" onclick=\"completePayment()\">已完成支付</button></div></div></div>\n<div class=\"modal\" id=\"chatSettingsModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3>对话设置</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('chatSettingsModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"setting-row\"><div class=\"setting-row-label\">模型温度</div><div class=\"slider-container\"><input type=\"range\" id=\"csTemp\" min=\"0\" max=\"2\" step=\"0.1\" value=\"0.7\" oninput=\"$('csTempVal').textContent=this.value\"><span class=\"slider-value\" id=\"csTempVal\">0.7</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">上下文数</div><div class=\"slider-container\"><input type=\"range\" id=\"csContext\" min=\"1\" max=\"50\" value=\"10\" oninput=\"$('csContextVal').textContent=this.value\"><span class=\"slider-value\" id=\"csContextVal\">10</span></div></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">流式输出</div><label class=\"switch\"><input type=\"checkbox\" id=\"csStream\" checked><span class=\"switch-slider\"></span></label></div>\n<div class=\"setting-row\"><div class=\"setting-row-label\">最大 Token</div><div class=\"slider-container\"><input type=\"range\" id=\"csMaxTokens\" min=\"256\" max=\"8192\" step=\"256\" value=\"2048\" oninput=\"$('csMaxTokensVal').textContent=this.value\"><span class=\"slider-value\" id=\"csMaxTokensVal\">2048</span></div></div>\n<button class=\"btn btn-primary\" style=\"width:100%;margin-top:16px\" onclick=\"saveChatSettings()\">保存设置</button>\n</div></div></div>\n<div class=\"modal\" id=\"shortcutModal\"><div class=\"modal-content\" style=\"max-width:450px\"><div class=\"modal-header\"><h3 id=\"shortcutModalTitle\">添加快捷短语</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('shortcutModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>名称</label><input type=\"text\" id=\"shortcutName\" placeholder=\"例如:翻译\"></div>\n<div class=\"form-group\"><label>触发词</label><input type=\"text\" id=\"shortcutTrigger\" placeholder=\"例如:/translate\"></div>\n<div class=\"form-group\"><label>内容</label><textarea id=\"shortcutContent\" rows=\"5\" placeholder=\"请将以下内容翻译成中文:&#10;&#10;{{input}}\"></textarea></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveShortcutFromModal()\">保存</button>\n</div></div></div>\n<div class=\"modal\" id=\"memoryModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>添加记忆</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('memoryModal')\">✕</button></div><div class=\"modal-body\">\n<div class=\"form-group\"><label>记忆内容<br><small style=\"color:var(--text2)\">AI 会在对话中记住这些信息</small></label><textarea id=\"memoryContent\" rows=\"4\" placeholder=\"例如:我是一名前端开发者,喜欢使用 React 和 TypeScript\"></textarea></div>\n<div class=\"form-group\"><label>分类</label><select id=\"memoryModalCategory\" style=\"width:100%\"><option value=\"个人\">👤 个人信息</option><option value=\"工作\">💼 工作相关</option><option value=\"偏好\">⭐ 偏好设置</option><option value=\"其他\">📝 其他</option></select></div>\n<button class=\"btn btn-primary\" style=\"width:100%\" onclick=\"saveMemoryFromModal()\">添加记忆</button>\n</div></div></div>\n<div class=\"modal\" id=\"hotkeyHelpModal\"><div class=\"modal-content\" style=\"max-width:500px\"><div class=\"modal-header\"><h3>⌨️ 快捷键</h3><button class=\"btn btn-icon btn-ghost\" onclick=\"closeModal('hotkeyHelpModal')\">✕</button></div><div class=\"modal-body\">\n<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + N</span><span>新建对话</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + E</span><span>快捷助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ,</span><span>打开设置</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + /</span><span>快捷键帮助</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Enter</span><span>发送消息</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Shift + Enter</span><span>换行</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Escape</span><span>关闭弹窗</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + [</span><span>切换助手</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + ]</span><span>切换话题</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + +</span><span>放大界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + -</span><span>缩小界面</span></div>\n<div class=\"hotkey-help-item\"><span class=\"hotkey-help-key\">Ctrl + 0</span><span>重置缩放</span></div>\n</div>\n</div></div></div>\n<script>\nvar currentUser=null,authToken=localStorage.getItem('token'),isRegisterMode=false,currentPaymentId=null;\nvar providers=JSON.parse(localStorage.getItem('providers')||'null')||[\n{id:'openai',name:'OpenAI',url:'https://api.openai.com/v1',key:'',type:'openai',models:[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'}]},\n{id:'claude',name:'Claude',url:'https://api.anthropic.com/v1',key:'',type:'claude',models:[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'}]},\n{id:'deepseek',name:'DeepSeek',url:'https://api.deepseek.com/v1',key:'',type:'openai',models:[{id:'deepseek-chat',name:'DeepSeek Chat'},{id:'deepseek-reasoner',name:'DeepSeek R1'}]},\n{id:'qwen',name:'通义千问',url:'https://dashscope.aliyuncs.com/compatible-mode/v1',key:'',type:'openai',models:[{id:'qwen-turbo',name:'Qwen Turbo'},{id:'qwen-plus',name:'Qwen Plus'}]},\n{id:'zhipu',name:'智谱AI',url:'https://open.bigmodel.cn/api/paas/v4',key:'',type:'openai',models:[{id:'glm-4',name:'GLM-4'}]},\n{id:'moonshot',name:'Moonshot',url:'https://api.moonshot.cn/v1',key:'',type:'openai',models:[{id:'moonshot-v1-8k',name:'Moonshot V1'}]}\n];\nvar currentProviderId=providers[0]?providers[0].id:null;\nvar chats=JSON.parse(localStorage.getItem('chats')||'[]'),currentChatId=null;\nvar notes=[],currentNoteId=null,memories=[],shortcuts=JSON.parse(localStorage.getItem('shortcuts')||'[]'),uploadedDoc=null;\nvar assistants=JSON.parse(localStorage.getItem('assistants')||'null')||[\n{id:'default',name:'默认助手',emoji:'😀',desc:'通用AI助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048,isSystem:true},\n{id:'pm',name:'产品经理',emoji:'👨‍💼',desc:'产品规划与需求分析',prompt:'你是一位资深产品经理,擅长产品规划、需求分析、用户研究和项目管理。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'strategy',name:'策略产品经理',emoji:'🎯',desc:'产品策略与商业分析',prompt:'你是一位策略产品经理,擅长市场分析、竞品研究和商业模式设计。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'community',name:'社群运营',emoji:'👥',desc:'社群管理与用户运营',prompt:'你是一位社群运营专家,擅长社群管理、用户增长和活动策划。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'content',name:'内容运营',emoji:'🐰',desc:'内容创作与传播',prompt:'你是一位内容运营专家,擅长内容策划、文案撰写和内容分发。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'merchant',name:'商家运营',emoji:'🛍️',desc:'商家管理与服务',prompt:'你是一位商家运营专家,擅长商家管理、招商和商家服务。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'product',name:'产品运营',emoji:'🚀',desc:'产品推广与增长',prompt:'你是一位产品运营专家,擅长产品推广、用户增长和数据分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'sales',name:'销售运营',emoji:'💼',desc:'销售策略与客户管理',prompt:'你是一位销售运营专家,擅长销售策略、客户管理和业绩分析。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'user',name:'用户运营',emoji:'👤',desc:'用户生命周期管理',prompt:'你是一位用户运营专家,擅长用户分层、用户激励和用户留存。',temp:0.7,context:10,stream:true,maxTokens:2048},\n{id:'marketing',name:'市场营销',emoji:'📢',desc:'品牌推广与营销策划',prompt:'你是一位市场营销专家,擅长品牌策划、营销活动和市场推广。',temp:0.8,context:10,stream:true,maxTokens:2048},\n{id:'coder',name:'程序员',emoji:'💻',desc:'代码开发与技术咨询',prompt:'你是一位资深程序员,擅长多种编程语言,能够帮助用户解决编程问题、代码审查和技术方案设计。',temp:0.5,context:15,stream:true,maxTokens:4096},\n{id:'translator',name:'翻译专家',emoji:'🌐',desc:'多语言翻译',prompt:'你是一位专业翻译,精通中英日韩等多种语言,能够准确传达原文含义并保持语言风格。',temp:0.3,context:5,stream:true,maxTokens:2048}\n];\nvar currentAssistantId=assistants[0]?assistants[0].id:null;\nvar chatSettings={temp:0.7,context:10,stream:false,maxTokens:2048};\nfunction $(id){return document.getElementById(id)}\nfunction save(){localStorage.setItem('providers',JSON.stringify(providers))}\nfunction saveChats(){localStorage.setItem('chats',JSON.stringify(chats))}\nfunction saveShortcuts(){localStorage.setItem('shortcuts',JSON.stringify(shortcuts))}\nfunction saveAssistants(){localStorage.setItem('assistants',JSON.stringify(assistants))}\nfunction escapeHtml(t){return t.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>')}\nfunction closeModal(id){$(id).classList.remove('show')}\nfunction showModal(id){$(id).classList.add('show')}\nfunction setAccent(c){document.documentElement.style.setProperty('--accent',c)}\nfunction toggleCollapse(el){var content=el.nextElementSibling;content.classList.toggle('show');el.querySelector('span:last-child').textContent=content.classList.contains('show')?'▲':'▼'}\nfunction api(path,options){options=options||{};var headers=Object.assign({'Content-Type':'application/json'},options.headers||{});if(authToken)headers['Authorization']='Bearer '+authToken;return fetch(path,Object.assign({},options,{headers:headers})).then(function(res){if(!res.ok)return res.json().then(function(e){throw new Error(e.detail||'Error')});return res.json()})}\ndocument.querySelectorAll('.nav-item[data-page]').forEach(function(n){n.onclick=function(){document.querySelectorAll('.nav-item').forEach(function(i){i.classList.remove('active')});document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});n.classList.add('active');var page=$('page-'+n.dataset.page);if(page)page.classList.add('active')}});\nfunction showAuthModal(){isRegisterMode=false;updateAuthUI();showModal('authModal')}\nfunction toggleAuthMode(){isRegisterMode=!isRegisterMode;updateAuthUI()}\nfunction updateAuthUI(){$('authTitle').textContent=isRegisterMode?'注册':'登录';$('authSubmit').textContent=isRegisterMode?'注册':'登录';$('authEmailGroup').style.display=isRegisterMode?'block':'none';$('authSwitch').innerHTML=isRegisterMode?'已有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">登录</a>':'没有账号?<a href=\"#\" onclick=\"toggleAuthMode()\" style=\"color:var(--accent)\">注册</a>'}\nfunction submitAuth(){var username=$('authUsername').value.trim(),password=$('authPassword').value;if(!username||!password)return alert('请填写');if(isRegisterMode){api('/api/auth/register',{method:'POST',body:JSON.stringify({username:username,password:password,email:$('authEmail').value})}).then(function(){alert('注册成功');toggleAuthMode()}).catch(function(e){alert(e.message)})}else{api('/api/auth/login',{method:'POST',body:JSON.stringify({username:username,password:password})}).then(function(res){authToken=res.token;localStorage.setItem('token',authToken);currentUser=res.user;closeModal('authModal');updateUserUI();loadUserData()}).catch(function(e){alert(e.message)})}}\nfunction checkAuth(){if(!authToken)return;api('/api/auth/me').then(function(u){currentUser=u;updateUserUI();loadUserData()}).catch(function(){authToken=null;localStorage.removeItem('token')})}\nfunction updateUserUI(){$('navUserName').textContent=currentUser?currentUser.username:'登录'}\nfunction loadUserData(){if(!currentUser)return;api('/api/notes').then(function(n){notes=n;renderNotes()}).catch(function(){});api('/api/memories').then(function(m){memories=m;renderMemories()}).catch(function(){})}\nfunction showPricing(){api('/api/plans').then(function(plans){var html='';for(var key in plans){var p=plans[key];html+='<div class=\"price-card\" onclick=\"selectPlan(\\''+key+'\\')\"><h4>'+p.name+'</h4><div class=\"price\">'+(p.price>0?'¥'+p.price:'免费')+'<span>/月</span></div><ul>'+p.features.map(function(f){return'<li>'+f+'</li>'}).join('')+'</ul><button class=\"btn '+(key==='free'?'btn-ghost':'btn-primary')+'\" style=\"width:100%\">'+(key==='free'?'当前':'订阅')+'</button></div>'}$('priceCards').innerHTML=html;showModal('pricingModal')}).catch(function(e){alert(e.message)})}\nfunction selectPlan(plan){if(plan==='free')return;if(!currentUser){closeModal('pricingModal');showAuthModal();return}api('/api/payments/create',{method:'POST',body:JSON.stringify({plan:plan})}).then(function(res){currentPaymentId=res.payment_id;$('paymentInfo').innerHTML='<h4>'+plan+'</h4><div style=\"font-size:32px;font-weight:700;color:var(--accent)\">¥'+res.amount+'</div>';closeModal('pricingModal');showModal('paymentModal')}).catch(function(e){alert(e.message)})}\nfunction completePayment(){if(!currentPaymentId)return;api('/api/payments/'+currentPaymentId+'/complete',{method:'POST'}).then(function(){alert('支付成功!');closeModal('paymentModal');checkAuth()}).catch(function(e){alert(e.message)})}\nfunction checkUpdate(){alert('当前已是最新版本')}\nfunction showChatSettings(){$('csTemp').value=chatSettings.temp;$('csTempVal').textContent=chatSettings.temp;$('csContext').value=chatSettings.context;$('csContextVal').textContent=chatSettings.context;$('csStream').checked=chatSettings.stream;$('csMaxTokens').value=chatSettings.maxTokens;$('csMaxTokensVal').textContent=chatSettings.maxTokens;showModal('chatSettingsModal')}\nfunction saveChatSettings(){chatSettings.temp=parseFloat($('csTemp').value);chatSettings.context=parseInt($('csContext').value);chatSettings.stream=$('csStream').checked;chatSettings.maxTokens=parseInt($('csMaxTokens').value);closeModal('chatSettingsModal');alert('设置已保存')}\n</script>\n<script>\n// 助手管理\nfunction renderAssistants(){var html=assistants.map(function(a){return'<div class=\"assistant-card'+(a.id===currentAssistantId?' active':'')+'\" onclick=\"selectAssistant(\\''+a.id+'\\')\"><div class=\"assistant-avatar\" style=\"background:'+(a.isSystem?'linear-gradient(135deg,#fef3c7,#fde68a)':'linear-gradient(135deg,#e0e7ff,#c7d2fe)')+'\">'+a.emoji+'</div><div class=\"assistant-info\"><div class=\"assistant-name\">'+a.name+'</div><div class=\"assistant-desc\">'+a.desc+'</div></div>'+(a.isSystem?'<span class=\"assistant-tag\">系统</span>':'')+'</div>'}).join('');$('assistantList').innerHTML=html;updateAssistantSelect()}\nfunction selectAssistant(id){currentAssistantId=id;var a=assistants.find(function(x){return x.id===id});if(a){$('aName').value=a.name;$('aEmoji').value=a.emoji;$('aDesc').value=a.desc;$('aPrompt').value=a.prompt;$('aTemp').value=a.temp;$('aTempVal').textContent=a.temp;$('aContext').value=a.context;$('aContextVal').textContent=a.context;$('aStream').checked=a.stream;$('aMaxTokens').value=a.maxTokens;$('aMaxTokensVal').textContent=a.maxTokens}renderAssistants()}\nfunction addAssistant(){var id='a_'+Date.now();assistants.push({id:id,name:'新助手',emoji:'🤖',desc:'自定义助手',prompt:'你是一个有帮助的AI助手。',temp:0.7,context:10,stream:true,maxTokens:2048});saveAssistants();renderAssistants();selectAssistant(id)}\nfunction saveAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a){a.name=$('aName').value;a.emoji=$('aEmoji').value;a.desc=$('aDesc').value;a.prompt=$('aPrompt').value;a.temp=parseFloat($('aTemp').value);a.context=parseInt($('aContext').value);a.stream=$('aStream').checked;a.maxTokens=parseInt($('aMaxTokens').value);saveAssistants();renderAssistants();alert('保存成功')}}\nfunction deleteAssistant(){var a=assistants.find(function(x){return x.id===currentAssistantId});if(a&&a.isSystem)return alert('系统助手不能删除');if(!confirm('确定删除?'))return;assistants=assistants.filter(function(x){return x.id!==currentAssistantId});saveAssistants();currentAssistantId=assistants[0]?assistants[0].id:null;renderAssistants();if(currentAssistantId)selectAssistant(currentAssistantId)}\nfunction switchAssistantTab(tab){document.querySelectorAll('#page-assistants .tab').forEach(function(t){t.classList.remove('active')});event.target.classList.add('active');$('assistantTabInfo').style.display=tab==='info'?'block':'none';$('assistantTabSettings').style.display=tab==='settings'?'block':'none'}\nfunction updateAssistantSelect(){$('chatAssistant').innerHTML=assistants.map(function(a){return'<option value=\"'+a.id+'\">'+a.emoji+' '+a.name+'</option>'}).join('')}\nfunction onAssistantChange(){var a=assistants.find(function(x){return x.id===$('chatAssistant').value});if(a){chatSettings.temp=a.temp;chatSettings.context=a.context;chatSettings.stream=a.stream;chatSettings.maxTokens=a.maxTokens}}\n// 聊天\nfunction renderChats(){var html='';if(chats.length===0){html='<div class=\"empty-state\"><span>📭</span><p>暂无对话</p></div>'}else{chats.forEach(function(c){html+='<div class=\"sidebar-item'+(c.id===currentChatId?' active':'')+'\" onclick=\"selectChat(\\''+c.id+'\\')\" oncontextmenu=\"showChatMenu(event,\\''+c.id+'\\')\"><div class=\"sidebar-item-icon\">💬</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(c.title||'新对话')+'</div><div class=\"sidebar-item-desc\">'+(c.messages?c.messages.length:0)+' 条消息</div></div><button class=\"btn btn-ghost btn-sm chat-delete-btn\" onclick=\"event.stopPropagation();deleteChat(\\''+c.id+'\\')\" style=\"opacity:0;padding:4px 8px\">🗑️</button></div>'})}$('chatList').innerHTML=html}\nfunction selectChat(id){currentChatId=id;renderChats();renderMessages()}\nfunction newChat(){var id='chat_'+Date.now();chats.unshift({id:id,title:'新对话',messages:[],provider:providers[0]?providers[0].id:'',model:providers[0]&&providers[0].models[0]?providers[0].models[0].id:'',assistant:currentAssistantId});saveChats();renderChats();selectChat(id)}\nfunction renderMessages(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages||chat.messages.length===0){$('chatMessages').innerHTML='<div class=\"empty-state\"><span>💬</span><p>开始新的对话</p><p style=\"font-size:12px;margin-top:8px;color:var(--text2)\">Ctrl+N 新建对话 · Enter 发送消息</p></div>';return}var html='';chat.messages.forEach(function(m,i){var actions=m.role==='assistant'?'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"regenerateMessage('+i+')\" title=\"重新生成\">🔄</button><button class=\"message-action-btn\" onclick=\"readAloud('+i+')\" title=\"朗读\">🔊</button></div>':'<div class=\"message-actions\"><button class=\"message-action-btn\" onclick=\"copyMessage('+i+')\" title=\"复制\">📋</button><button class=\"message-action-btn\" onclick=\"editMessage('+i+')\" title=\"编辑\">✏️</button></div>';html+='<div class=\"message '+m.role+(m.error?' error':'')+'\"><div class=\"message-content\">'+(m.role==='assistant'?marked.parse(m.content):escapeHtml(m.content))+'</div>'+actions+'</div>'});$('chatMessages').innerHTML=html;$('chatMessages').scrollTop=$('chatMessages').scrollHeight;hljs.highlightAll()}\nfunction handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage()}e.target.style.height='auto';e.target.style.height=Math.min(e.target.scrollHeight,150)+'px'}\nfunction sendMessage(){var input=$('chatInput'),text=input.value.trim();if(!text)return;input.value='';input.style.height='auto';var chat=chats.find(function(c){return c.id===currentChatId});if(!chat){newChat();chat=chats[0]}chat.messages.push({role:'user',content:text});if(chat.messages.length===1)chat.title=text.slice(0,25);saveChats();renderChats();renderMessages();var p=providers.find(function(x){return x.id===$('chatProvider').value}),key=p?cleanApiKey(p.key):'',stream=chatSettings.stream;console.log('Provider:',p?p.name:'none','Key length:',key?key.length:0,'URL:',p?p.url:'none');var assistant=assistants.find(function(x){return x.id===$('chatAssistant').value});var messages=chat.messages.filter(function(m){return!m.error}).slice(-chatSettings.context).map(function(m){return{role:m.role,content:m.content}});if(assistant&&assistant.prompt){messages.unshift({role:'system',content:assistant.prompt})}$('sendBtn').disabled=true;var providerType=p?p.type:'openai';var payload={provider:providerType==='claude'?'claude':'custom',model:$('chatModel').value,messages:messages,custom_url:p?p.url:'',api_key:key,stream:stream,temperature:chatSettings.temp,max_tokens:chatSettings.maxTokens};console.log('Sending payload:',payload);if(stream){chat.messages.push({role:'assistant',content:''});renderMessages();var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(response){var reader=response.body.getReader(),decoder=new TextDecoder(),content='';function read(){reader.read().then(function(result){if(result.done){saveChats();$('sendBtn').disabled=false;return}var chunk=decoder.decode(result.value),lines=chunk.split('\\n');lines.forEach(function(line){if(line.indexOf('data: ')===0){var data=line.slice(6);if(data==='[DONE]')return;try{var parsed=JSON.parse(data);console.log('Stream chunk:',parsed);var delta=parsed.choices&&parsed.choices[0]&&parsed.choices[0].delta&&parsed.choices[0].delta.content;if(delta){content+=delta;chat.messages[chat.messages.length-1].content=content;renderMessages()}}catch(e){console.log('Parse error:',e,data)}}});read()})}read()}).catch(function(e){chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}else{var headers={'Content-Type':'application/json'};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/v1/chat/completions',{method:'POST',headers:headers,body:JSON.stringify(payload)}).then(function(r){return r.json()}).then(function(data){var content='';if(data.error||data.detail){content=data.detail||JSON.stringify(data);chat.messages.push({role:'assistant',content:content,error:true})}else if(p&&p.type==='claude'){content=data.content&&data.content[0]?data.content[0].text:JSON.stringify(data);chat.messages.push({role:'assistant',content:content})}else{content=data.choices&&data.choices[0]&&data.choices[0].message?data.choices[0].message.content:JSON.stringify(data);chat.messages.push({role:'assistant',content:content})}saveChats();renderMessages();$('sendBtn').disabled=false}).catch(function(e){chat.messages.push({role:'assistant',content:'错误: '+e.message,error:true});saveChats();renderMessages();$('sendBtn').disabled=false})}}\nfunction clearChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&confirm('确定清空?')){chat.messages=[];saveChats();renderMessages()}}\nfunction exportChat(){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click()}\nfunction updateChatProviders(){var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');$('chatProvider').innerHTML=html;if($('defaultChatProvider'))$('defaultChatProvider').innerHTML=html;onProviderChange()}\nfunction onProviderChange(){var p=providers.find(function(x){return x.id===$('chatProvider').value});$('chatModel').innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\n</script>\n<script>\n// 模型服务\nfunction renderProviders(){var html=providers.map(function(p){return'<div class=\"sidebar-item'+(p.id===currentProviderId?' active':'')+'\" onclick=\"selectProvider(\\''+p.id+'\\')\"><div class=\"sidebar-item-icon\">'+p.name[0]+'</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+p.name+'</div><div class=\"sidebar-item-desc\">'+(p.models?p.models.length:0)+' 个模型</div></div><div style=\"width:8px;height:8px;border-radius:50%;background:'+(p.key?'var(--success)':'var(--text2)')+'\"></div></div>'}).join('');$('providerList').innerHTML=html}\nfunction selectProvider(id){currentProviderId=id;var p=providers.find(function(x){return x.id===id});if(p){$('pName').value=p.name;$('pUrl').value=p.url;$('pKey').value=p.key;$('pType').value=p.type||'openai';renderModels(p.models||[])}renderProviders()}\nfunction renderModels(models){if(models.length===0){$('modelList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无模型</p></div>';return}var html=models.map(function(m){return'<div class=\"list-item\"><div class=\"list-item-icon\">🤖</div><div class=\"list-item-content\"><div class=\"list-item-title\">'+m.name+'</div><div class=\"list-item-desc\">'+m.id+'</div></div><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteModel(\\''+m.id+'\\')\">🗑️</button></div>'}).join('');$('modelList').innerHTML=html}\nfunction addProvider(){var id='p_'+Date.now();providers.push({id:id,name:'新服务',url:'',key:'',type:'openai',models:[]});save();renderProviders();selectProvider(id);updateChatProviders()}\nfunction saveProvider(){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.name=$('pName').value;p.url=$('pUrl').value;p.key=cleanApiKey($('pKey').value);p.type=$('pType').value;save();renderProviders();updateChatProviders();alert('保存成功')}}\nfunction deleteProvider(){if(!confirm('确定删除?'))return;providers=providers.filter(function(p){return p.id!==currentProviderId});save();currentProviderId=providers[0]?providers[0].id:null;renderProviders();if(currentProviderId)selectProvider(currentProviderId);updateChatProviders()}\nfunction cleanApiKey(key){if(!key)return'';var result='';for(var i=0;i<key.length;i++){var c=key.charCodeAt(i);if(c>=32&&c<127)result+=key[i]}return result.trim()}\nfunction testProvider(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){if(data.success){alert('✓ 连接成功')}else{alert('✗ 失败: '+(data.error||'未知错误'))}}).catch(function(e){alert('✗ 失败: '+e.message)})}\nfunction fetchModels(){var url=$('pUrl').value,key=cleanApiKey($('pKey').value);if(!url||!key){alert('请填写 API 地址和 API Key');return}fetch('/api/proxy/models',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:url,key:key})}).then(function(r){return r.json()}).then(function(data){var p=providers.find(function(x){return x.id===currentProviderId});if(data.error){alert('获取失败: '+data.error);return}if(p&&data.data){p.models=data.data.slice(0,50).map(function(m){return{id:m.id,name:m.id}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else if(p&&data.models){p.models=data.models.slice(0,50).map(function(m){return{id:m.id||m,name:m.id||m}});save();renderModels(p.models);updateChatProviders();alert('获取成功: '+p.models.length+' 个模型')}else{alert('未找到模型列表')}}).catch(function(e){alert('失败: '+e.message)})}\nfunction addModel(){var name=prompt('模型名称:');if(!name)return;var id=prompt('模型ID:',name);if(!id)return;var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models||[];p.models.push({id:id,name:name});save();renderModels(p.models);updateChatProviders()}}\nfunction deleteModel(mid){var p=providers.find(function(x){return x.id===currentProviderId});if(p){p.models=p.models.filter(function(m){return m.id!==mid});save();renderModels(p.models);updateChatProviders()}}\n// 笔记\nfunction renderNotes(){if(notes.length===0){$('noteList').innerHTML='<div class=\"empty-state\"><span>📭</span><p>暂无笔记</p></div>';return}var html=notes.map(function(n){return'<div class=\"sidebar-item'+(n.id===currentNoteId?' active':'')+'\" onclick=\"selectNote(\\''+n.id+'\\')\"><div class=\"sidebar-item-icon\">📝</div><div class=\"sidebar-item-info\"><div class=\"sidebar-item-title\">'+(n.title||'无标题')+'</div></div></div>'}).join('');$('noteList').innerHTML=html}\nfunction selectNote(id){currentNoteId=id;var n=notes.find(function(x){return x.id===id});if(n){$('noteTitle').value=n.title;$('noteContent').value=n.content}renderNotes()}\nfunction newNote(){if(!currentUser)return alert('请先登录');api('/api/notes',{method:'POST',body:JSON.stringify({title:'新笔记',content:'',tags:''})}).then(function(res){notes.unshift({id:res.id,title:'新笔记',content:''});renderNotes();selectNote(res.id)}).catch(function(e){alert(e.message)})}\nfunction saveNote(){if(!currentNoteId)return;api('/api/notes/'+currentNoteId,{method:'PUT',body:JSON.stringify({title:$('noteTitle').value,content:$('noteContent').value,tags:''})}).then(function(){var n=notes.find(function(x){return x.id===currentNoteId});if(n){n.title=$('noteTitle').value;n.content=$('noteContent').value}renderNotes();alert('保存成功')}).catch(function(e){alert(e.message)})}\nfunction deleteNote(){if(!currentNoteId||!confirm('确定删除?'))return;api('/api/notes/'+currentNoteId,{method:'DELETE'}).then(function(){notes=notes.filter(function(n){return n.id!==currentNoteId});currentNoteId=notes[0]?notes[0].id:null;renderNotes();if(currentNoteId)selectNote(currentNoteId);else{$('noteTitle').value='';$('noteContent').value=''}}).catch(function(e){alert(e.message)})}\n// 记忆\nfunction renderMemories(){if(memories.length===0){$('memoryList').innerHTML='<div class=\"empty-state\" style=\"padding:60px\"><span style=\"font-size:64px;display:block;margin-bottom:16px;opacity:0.5\">🧠</span><p style=\"font-size:16px;margin-bottom:8px\">暂无记忆</p><p style=\"font-size:13px\">开始添加您的第一条记忆吧</p><button class=\"btn btn-primary\" style=\"margin-top:20px\" onclick=\"showAddMemoryModal()\">+ 添加您的第一条记忆</button></div>';return}var html=memories.map(function(m){return'<div class=\"memory-item\"><div class=\"memory-item-content\">'+escapeHtml(m.content)+'<div class=\"memory-item-meta\">'+m.category+' · '+(m.created_at||'刚刚')+'</div></div><div class=\"memory-item-actions\"><button class=\"btn btn-ghost btn-sm\" onclick=\"editMemory('+m.id+')\">✏️</button><button class=\"btn btn-ghost btn-sm\" onclick=\"deleteMemory('+m.id+')\">🗑️</button></div></div>'}).join('');$('memoryList').innerHTML=html}\nfunction showAddMemoryModal(){$('memoryContent').value='';$('memoryModalCategory').value='个人';showModal('memoryModal')}\nfunction saveMemoryFromModal(){var content=$('memoryContent').value.trim();if(!content)return alert('请输入记忆内容');if(!currentUser){closeModal('memoryModal');return alert('请先登录')}api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryModalCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();closeModal('memoryModal');alert('记忆添加成功')}).catch(function(e){alert(e.message)})}\nfunction addMemoryContent(content){if(!currentUser)return alert('请先登录');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory')?$('memoryCategory').value:'个人'})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction editMemory(id){var m=memories.find(function(x){return x.id===id});if(!m)return;var content=prompt('编辑记忆:',m.content);if(content&&content.trim()){api('/api/memories/'+id,{method:'PUT',body:JSON.stringify({content:content.trim(),category:m.category})}).then(function(){m.content=content.trim();renderMemories()}).catch(function(e){alert(e.message)})}}\nfunction addMemory(){if(!currentUser)return alert('请先登录');var content=$('newMemory').value.trim();if(!content)return alert('请输入内容');api('/api/memories',{method:'POST',body:JSON.stringify({content:content,category:$('memoryCategory').value})}).then(function(){return api('/api/memories')}).then(function(m){memories=m;renderMemories();$('newMemory').value='';alert('添加成功')}).catch(function(e){alert(e.message)})}\nfunction deleteMemory(id){if(!confirm('确定删除?'))return;api('/api/memories/'+id,{method:'DELETE'}).then(function(){memories=memories.filter(function(m){return m.id!==id});renderMemories()}).catch(function(e){alert(e.message)})}\n// 搜索设置\nfunction onSearchProviderChange(){var provider=$('searchProvider').value;$('searchZhipuSection').style.display=provider==='zhipu'?'block':'none';$('searchSearxngSection').style.display=provider==='searxng'?'block':'none'}\nfunction togglePassword(id){var input=$(id);input.type=input.type==='password'?'text':'password'}\nfunction testSearchKey(){var key=$('zhipuSearchKey').value;if(!key)return alert('请输入 API 密钥');alert('API 密钥格式正确')}\nfunction saveSearchSettings(){var settings={provider:$('searchProvider').value,enabled:$('searchEnabled').checked,resultCount:$('searchResultCount').value,blacklist:$('searchBlacklist').value};localStorage.setItem('searchSettings',JSON.stringify(settings));alert('搜索设置已保存')}\nfunction copyText(text){navigator.clipboard.writeText(text).then(function(){alert('已复制到剪贴板')}).catch(function(){prompt('请手动复制:',text)})}\n// 对话功能增强\nfunction searchChats(){var input=$('chatSearchInput');input.style.display=input.style.display==='none'?'block':'none';if(input.style.display==='block')input.focus()}\nfunction filterChats(keyword){var items=document.querySelectorAll('#chatList .sidebar-item');items.forEach(function(item){var title=item.querySelector('.sidebar-item-title').textContent.toLowerCase();item.style.display=title.includes(keyword.toLowerCase())?'flex':'none'})}\nfunction toggleWebSearch(){var btn=$('webSearchBtn');btn.classList.toggle('btn-primary');btn.classList.toggle('btn-ghost');alert(btn.classList.contains('btn-primary')?'网络搜索已启用':'网络搜索已关闭')}\nfunction uploadImage(){alert('图片上传功能开发中')}\nfunction uploadFile(){alert('文件上传功能开发中')}\nfunction voiceInput(){alert('语音输入功能开发中')}\nfunction stopGeneration(){alert('已停止生成')}\nfunction copyMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]){navigator.clipboard.writeText(chat.messages[index].content).then(function(){alert('已复制')})}}\nfunction regenerateMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat)return;chat.messages=chat.messages.slice(0,index);saveChats();renderMessages();var lastUserMsg=chat.messages.filter(function(m){return m.role==='user'}).pop();if(lastUserMsg){$('chatInput').value=lastUserMsg.content;sendMessage()}}\nfunction editMessage(index){var chat=chats.find(function(c){return c.id===currentChatId});if(!chat||!chat.messages[index])return;var newContent=prompt('编辑消息:',chat.messages[index].content);if(newContent!==null){chat.messages[index].content=newContent;saveChats();renderMessages()}}\nfunction readAloud(index){var chat=chats.find(function(c){return c.id===currentChatId});if(chat&&chat.messages[index]&&'speechSynthesis' in window){var utterance=new SpeechSynthesisUtterance(chat.messages[index].content);utterance.lang='zh-CN';speechSynthesis.speak(utterance)}else{alert('您的浏览器不支持语音合成')}}\nfunction deleteChat(id){if(!confirm('确定删除此对话?'))return;chats=chats.filter(function(c){return c.id!==id});saveChats();if(currentChatId===id){currentChatId=chats[0]?chats[0].id:null;if(!currentChatId)newChat();else selectChat(currentChatId)}renderChats();showToast('对话已删除')}\nfunction showChatMenu(e,id){e.preventDefault();var menu=document.createElement('div');menu.className='context-menu';menu.innerHTML='<div onclick=\"renameChat(\\''+id+'\\')\">✏️ 重命名</div><div onclick=\"exportSingleChat(\\''+id+'\\')\">📥 导出</div><div onclick=\"deleteChat(\\''+id+'\\')\" style=\"color:var(--error)\">🗑️ 删除</div>';menu.style.cssText='position:fixed;left:'+e.clientX+'px;top:'+e.clientY+'px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:4px;z-index:1000;min-width:120px';document.body.appendChild(menu);setTimeout(function(){document.addEventListener('click',function handler(){menu.remove();document.removeEventListener('click',handler)})},0)}\nfunction renameChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var newTitle=prompt('重命名对话:',chat.title);if(newTitle){chat.title=newTitle;saveChats();renderChats();showToast('已重命名')}}\nfunction exportSingleChat(id){var chat=chats.find(function(c){return c.id===id});if(!chat)return;var text=chat.messages.map(function(m){return'['+m.role+']\\n'+m.content}).join('\\n\\n---\\n\\n');var blob=new Blob([text],{type:'text/plain'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=(chat.title||'chat')+'.txt';a.click();showToast('已导出')}\n// 笔记设置\nfunction selectNotesDir(){alert('请在文件管理器中选择目录')}\nfunction applyNotesDir(){alert('工作目录已应用')}\nfunction resetNotesDir(){$('notesWorkDir').value='C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data\\\\Notes';alert('已重置为默认目录')}\n// MCP\nfunction refreshMcpServers(){alert('正在刷新 MCP 服务器状态...')}\nfunction showAddMcpModal(){alert('添加 MCP 服务器功能开发中')}\n// 数据管理\nfunction openDataDir(){alert('请在文件管理器中打开:C:\\\\Users\\\\legion\\\\AppData\\\\Roaming\\\\AIHub\\\\Data')}\nfunction clearChats(){if(!confirm('确定清除所有对话记录?'))return;chats=[];saveChats();renderChats();newChat();updateStats();alert('对话记录已清除')}\nfunction clearAssistants(){if(!confirm('确定清除所有自定义助手?'))return;assistants=assistants.filter(function(a){return a.isSystem});saveAssistants();renderAssistants();updateStats();alert('自定义助手已清除')}\nfunction updateStats(){$('statChats').textContent=chats.length;$('statAssistants').textContent=assistants.length;$('statShortcuts').textContent=shortcuts.length;var size=0;for(var key in localStorage){if(localStorage.hasOwnProperty(key)){size+=localStorage[key].length*2}}$('statStorage').textContent=Math.round(size/1024)+' KB'}\n// 默认模型\nfunction initDefaultModelSelects(){var types=['chat','translate','summary','code','quick'];var html=providers.map(function(p){return'<option value=\"'+p.id+'\">'+p.name+'</option>'}).join('');types.forEach(function(t){var pSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Provider');var mSel=$('default'+t.charAt(0).toUpperCase()+t.slice(1)+'Model');if(pSel){pSel.innerHTML=html;onDefaultProviderChange(t)}})}\nfunction onDefaultProviderChange(type){var pSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Provider');var mSel=$('default'+type.charAt(0).toUpperCase()+type.slice(1)+'Model');if(!pSel||!mSel)return;var p=providers.find(function(x){return x.id===pSel.value});mSel.innerHTML=(p&&p.models?p.models:[]).map(function(m){return'<option value=\"'+m.id+'\">'+m.name+'</option>'}).join('')}\nfunction saveDefaultModels(){var settings={chat:{provider:$('defaultChatProvider').value,model:$('defaultChatModel').value},translate:{provider:$('defaultTranslateProvider').value,model:$('defaultTranslateModel').value},summary:{provider:$('defaultSummaryProvider').value,model:$('defaultSummaryModel').value},code:{provider:$('defaultCodeProvider').value,model:$('defaultCodeModel').value},quick:{provider:$('defaultQuickProvider').value,model:$('defaultQuickModel').value}};localStorage.setItem('defaultModels',JSON.stringify(settings));alert('默认模型设置已保存')}\n// 显示设置\nfunction setTheme(mode){document.body.dataset.theme=mode;localStorage.setItem('theme',mode)}\nfunction setMsgFontSize(size){document.documentElement.style.setProperty('--msg-font-size',size+'px');event.target.nextElementSibling.textContent=size+'px'}\nfunction saveDisplaySettings(){var settings={theme:$('themeMode').value,msgFontSize:$('msgFontSize').value,msgStyle:$('msgStyle').value,showTimestamp:$('showTimestamp').checked,showAvatar:$('showAvatar').checked,showLineNumbers:$('showLineNumbers').checked,sidebarWidth:$('sidebarWidth').value,chatListWidth:$('chatListWidth').value,showNavButtons:$('showNavButtons').checked};localStorage.setItem('displaySettings',JSON.stringify(settings));alert('显示设置已保存')}\nfunction resetDisplaySettings(){$('themeMode').value='dark';$('msgFontSize').value=14;$('msgStyle').value='simple';$('showTimestamp').checked=false;$('showAvatar').checked=true;$('showLineNumbers').checked=false;$('sidebarWidth').value=220;$('chatListWidth').value=280;$('showNavButtons').checked=true;alert('已重置为默认设置')}\n// 常规设置\nfunction saveGeneralSettings(){var settings={language:$('appLanguage').value,temp:parseFloat($('defaultTemp').value),topP:parseFloat($('defaultTopP').value),context:parseInt($('defaultContext').value),maxTokens:parseInt($('defaultMaxTokens').value),stream:$('defaultStream').checked,autoScroll:$('autoScroll').checked,msgSound:$('msgSound').checked,autoTitle:$('autoTitle').checked,enableLatex:$('enableLatex').checked,codeHighlight:$('codeHighlight').checked,codeLineNumbers:$('codeLineNumbers').checked,enterSend:$('enterSend').checked,ctrlEnterNewline:$('ctrlEnterNewline').checked,autoFocus:$('autoFocus').checked};localStorage.setItem('generalSettings',JSON.stringify(settings));chatSettings.temp=settings.temp;chatSettings.context=settings.context;chatSettings.maxTokens=settings.maxTokens;chatSettings.stream=settings.stream;alert('常规设置已保存')}\n// 快捷短语\nfunction renderShortcuts(){if(shortcuts.length===0){$('shortcutList').innerHTML='<div class=\"empty-state\" style=\"padding:40px\"><span>⚡</span><p>暂无快捷短语</p><p style=\"font-size:12px;margin-top:8px\">点击右上角 + 添加</p></div>';return}var html=shortcuts.map(function(s,i){return'<div class=\"shortcut-item\" onclick=\"editShortcut('+i+')\"><span class=\"shortcut-item-icon\">🌐</span><span class=\"shortcut-item-name\">'+s.name+'</span></div>'}).join('');$('shortcutList').innerHTML=html}\nfunction showAddShortcutModal(){$('shortcutModalTitle').textContent='添加快捷短语';$('shortcutName').value='';$('shortcutTrigger').value='';$('shortcutContent').value='';$('shortcutModal').dataset.editIndex='';showModal('shortcutModal')}\nfunction editShortcut(i){$('shortcutModalTitle').textContent='编辑快捷短语';$('shortcutName').value=shortcuts[i].name;$('shortcutTrigger').value=shortcuts[i].trigger||'';$('shortcutContent').value=shortcuts[i].content;$('shortcutModal').dataset.editIndex=i;showModal('shortcutModal')}\nfunction saveShortcutFromModal(){var name=$('shortcutName').value.trim(),content=$('shortcutContent').value.trim();if(!name||!content)return alert('请填写名称和内容');var idx=$('shortcutModal').dataset.editIndex;if(idx!==''){shortcuts[parseInt(idx)]={name:name,content:content,trigger:$('shortcutTrigger').value}}else{shortcuts.push({name:name,content:content,trigger:$('shortcutTrigger').value})}saveShortcuts();renderShortcuts();closeModal('shortcutModal')}\nfunction deleteShortcut(i){if(!confirm('确定?'))return;shortcuts.splice(i,1);saveShortcuts();renderShortcuts()}\nfunction useShortcut(i){$('chatInput').value=shortcuts[i].content;document.querySelector('.nav-item[data-page=\"chat\"]').click();$('chatInput').focus()}\n// 文档\nfunction handleFileUpload(e){var file=e.target.files[0];if(!file)return;var formData=new FormData();formData.append('file',file);var headers={};if(authToken)headers['Authorization']='Bearer '+authToken;fetch('/api/documents/parse',{method:'POST',headers:headers,body:formData}).then(function(r){return r.json()}).then(function(data){uploadedDoc=data;$('docContent').textContent=data.content;$('docResult').style.display='block'}).catch(function(e){alert('失败: '+e.message)})}\nfunction summarizeDoc(){if(!uploadedDoc)return;$('chatInput').value='请总结以下内容:\\n\\n'+uploadedDoc.content.slice(0,5000);document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\nfunction askAboutDoc(){if(!uploadedDoc)return;var q=prompt('请输入问题:');if(!q)return;$('chatInput').value='基于以下内容回答:\\n\\n'+uploadedDoc.content.slice(0,4000)+'\\n\\n问题:'+q;document.querySelector('.nav-item[data-page=\"chat\"]').click();sendMessage()}\n// 数据\nfunction exportAllData(){var data={providers:providers,chats:chats,shortcuts:shortcuts,assistants:assistants,time:new Date().toISOString()};var blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='ai-hub-backup.json';a.click()}\nfunction importData(){var input=document.createElement('input');input.type='file';input.accept='.json';input.onchange=function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){try{var data=JSON.parse(ev.target.result);if(data.providers){providers=data.providers;save()}if(data.chats){chats=data.chats;saveChats()}if(data.shortcuts){shortcuts=data.shortcuts;saveShortcuts()}if(data.assistants){assistants=data.assistants;saveAssistants()}alert('导入成功');location.reload()}catch(e){alert('失败: '+e.message)}};reader.readAsText(file)};input.click()}\nfunction clearAllData(){if(!confirm('确定清除所有数据?'))return;localStorage.clear();location.reload()}\n// 数据设置页面切换\nfunction switchDataTab(tab){document.querySelectorAll('.settings-sidebar-item').forEach(function(i){i.classList.remove('active')});event.target.classList.add('active');alert('切换到: '+tab+' 设置')}\n// 初始化\nmarked.setOptions({breaks:true,highlight:function(code,lang){return lang&&hljs.getLanguage(lang)?hljs.highlight(code,{language:lang}).value:code}});\nrenderProviders();if(providers.length)selectProvider(providers[0].id);updateChatProviders();initDefaultModelSelects();renderAssistants();if(assistants.length)selectAssistant(assistants[0].id);renderChats();if(chats.length===0)newChat();else selectChat(chats[0].id);renderShortcuts();renderNotes();renderMemories();checkAuth();updateStats();\ndocument.addEventListener('keydown',function(e){if((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();newChat();showToast('新建对话')}if((e.ctrlKey||e.metaKey)&&e.key==='/'){e.preventDefault();showModal('hotkeyHelpModal')}if((e.ctrlKey||e.metaKey)&&e.key===','){e.preventDefault();document.querySelector('.nav-item[data-page=\"general\"]').click()}if(e.key==='Escape')document.querySelectorAll('.modal.show').forEach(function(m){m.classList.remove('show')})});\nfunction showToast(msg){var toast=document.createElement('div');toast.className='toast';toast.textContent=msg;document.body.appendChild(toast);setTimeout(function(){toast.remove()},2000)}\nconsole.log('🤖 AI Hub v1.7.2');\n</script>\n</body>\n</html>\n"}, "6fe5183e6b2abaeb01fe585804eb8e97ee949366": {"t": 1785765503.8523982, "n": 22776, "h": "03c7468d1c68c4ce", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>API Gateway Chat</title>\n <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n <style>\n :root {\n --bg-primary: #1a1a2e;\n --bg-secondary: #16213e;\n --bg-chat: #0f0f23;\n --text-primary: #eee;\n --text-secondary: #aaa;\n --accent: #667eea;\n --user-msg: #4a5568;\n --assistant-msg: #2d3748;\n --error: #e53e3e;\n }\n .light-theme {\n --bg-primary: #f5f5f5;\n --bg-secondary: #e0e0e0;\n --bg-chat: #fff;\n --text-primary: #333;\n --text-secondary: #666;\n --user-msg: #e3f2fd;\n --assistant-msg: #f5f5f5;\n }\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: var(--bg-primary);\n color: var(--text-primary);\n height: 100vh;\n display: flex;\n }\n .sidebar {\n width: 280px;\n background: var(--bg-secondary);\n padding: 15px;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n }\n .sidebar h2 { margin-bottom: 15px; font-size: 18px; }\n .sidebar label { margin-top: 12px; font-size: 13px; color: var(--text-secondary); }\n .sidebar select, .sidebar input[type=\"text\"], .sidebar input[type=\"number\"] {\n margin-top: 5px;\n padding: 8px;\n border: none;\n border-radius: 6px;\n background: var(--bg-primary);\n color: var(--text-primary);\n font-size: 13px;\n width: 100%;\n }\n .sessions { margin-top: 15px; flex: 1; overflow-y: auto; }\n .session-item {\n padding: 10px;\n margin: 5px 0;\n background: var(--bg-primary);\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n justify-content: space-between;\n align-items: center;\n font-size: 13px;\n }\n .session-item:hover { opacity: 0.8; }\n .session-item.active { border-left: 3px solid var(--accent); }\n .session-item .delete { color: var(--error); cursor: pointer; padding: 2px 6px; }\n .btn-group { display: flex; gap: 8px; margin-top: 15px; flex-wrap: wrap; }\n .btn {\n padding: 8px 12px;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n font-size: 12px;\n flex: 1;\n min-width: 70px;\n }\n .btn-primary { background: var(--accent); color: #fff; }\n .btn-danger { background: var(--error); color: #fff; }\n .btn-secondary { background: var(--bg-primary); color: var(--text-primary); }\n .main { flex: 1; display: flex; flex-direction: column; padding: 15px; }\n .stats {\n display: flex;\n gap: 15px;\n margin-bottom: 10px;\n font-size: 13px;\n color: var(--text-secondary);\n }\n .chat-container {\n flex: 1;\n overflow-y: auto;\n padding: 15px;\n background: var(--bg-chat);\n border-radius: 12px;\n margin-bottom: 15px;\n }\n .message {\n max-width: 85%;\n padding: 12px 16px;\n margin-bottom: 12px;\n border-radius: 12px;\n line-height: 1.6;\n }\n .message.user { background: var(--user-msg); margin-left: auto; }\n .message.assistant { background: var(--assistant-msg); }\n .message.error { background: var(--error); color: #fff; }\n .message pre { margin: 10px 0; border-radius: 6px; overflow-x: auto; }\n .message code { font-family: 'Consolas', monospace; font-size: 14px; }\n .message p { margin: 8px 0; }\n .message table { border-collapse: collapse; margin: 10px 0; }\n .message th, .message td { border: 1px solid var(--text-secondary); padding: 8px; }\n .input-area { display: flex; gap: 10px; }\n .input-area textarea {\n flex: 1;\n padding: 12px;\n border: none;\n border-radius: 12px;\n background: var(--bg-chat);\n color: var(--text-primary);\n font-size: 14px;\n resize: none;\n height: 60px;\n }\n .input-area button {\n padding: 12px 25px;\n border: none;\n border-radius: 12px;\n background: var(--accent);\n color: #fff;\n font-size: 14px;\n cursor: pointer;\n }\n .input-area button:disabled { opacity: 0.5; cursor: not-allowed; }\n .toggle-theme {\n position: fixed;\n top: 10px;\n right: 10px;\n background: var(--bg-secondary);\n border: none;\n padding: 8px 12px;\n border-radius: 6px;\n cursor: pointer;\n font-size: 16px;\n }\n </style>\n</head>\n<body>\n <button class=\"toggle-theme\" onclick=\"toggleTheme()\">🌙</button>\n <div class=\"sidebar\">\n <h2>⚡ API Gateway</h2>\n <label>平台</label>\n <select id=\"provider\">\n <optgroup label=\"国际主流\">\n <option value=\"openai\">OpenAI</option>\n <option value=\"azure_openai\">Azure OpenAI</option>\n <option value=\"claude\">Anthropic Claude</option>\n <option value=\"gemini\">Google Gemini</option>\n <option value=\"vertex_ai\">Vertex AI</option>\n <option value=\"mistral\">Mistral</option>\n <option value=\"groq\">Groq</option>\n <option value=\"together\">Together</option>\n <option value=\"fireworks\">Fireworks</option>\n <option value=\"perplexity\">Perplexity</option>\n <option value=\"openrouter\">OpenRouter</option>\n <option value=\"grok\">Grok (xAI)</option>\n <option value=\"hyperbolic\">Hyperbolic</option>\n <option value=\"nvidia\">英伟达 NVIDIA</option>\n <option value=\"github_models\">GitHub Models</option>\n <option value=\"github_copilot\">GitHub Copilot</option>\n <option value=\"aws_bedrock\">AWS Bedrock</option>\n <option value=\"jina\">Jina</option>\n <option value=\"voyage\">Voyage AI</option>\n <option value=\"poe\">Poe</option>\n </optgroup>\n <optgroup label=\"国内平台\">\n <option value=\"deepseek\">深度求索 DeepSeek</option>\n <option value=\"zhipu\">智谱 GLM</option>\n <option value=\"moonshot\">月之暗面 Kimi</option>\n <option value=\"baichuan\">百川</option>\n <option value=\"yi\">零一万物</option>\n <option value=\"qwen\">阿里云百炼 Qwen</option>\n <option value=\"stepfun\">阶跃星辰</option>\n <option value=\"minimax\">MiniMax</option>\n <option value=\"doubao\">豆包</option>\n <option value=\"hunyuan\">腾讯混元</option>\n <option value=\"tencent_ti\">腾讯云 TI</option>\n <option value=\"baidu_qianfan\">百度云千帆</option>\n <option value=\"tianyi\">天翼云息壤</option>\n <option value=\"wuxinqiong\">无问芯穹</option>\n </optgroup>\n <optgroup label=\"API 聚合平台\">\n <option value=\"siliconflow\">硅基流动</option>\n <option value=\"aihubmix\">AiHubMix</option>\n <option value=\"ocoolai\">ocoolAI</option>\n <option value=\"alaya\">Alaya NeW</option>\n <option value=\"dmxapi\">DMXAPI</option>\n <option value=\"aionly\">唯一AI (AiOnly)</option>\n <option value=\"burncloud\">BurnCloud</option>\n <option value=\"tokenflux\">TokenFlux</option>\n <option value=\"ai302\">302.AI</option>\n <option value=\"cephalon\">Cephalon</option>\n <option value=\"lanfun\">蓝耘科技</option>\n <option value=\"ph8\">PH8 大模型开放平台</option>\n <option value=\"ppio\">PPIO 派欧云</option>\n <option value=\"qiniu\">七牛云 AI 推理</option>\n <option value=\"longcat\">longcat</option>\n </optgroup>\n <optgroup label=\"本地/自托管\">\n <option value=\"ollama\">Ollama</option>\n <option value=\"lmstudio\">LM Studio</option>\n <option value=\"gpustack\">GPUStack</option>\n <option value=\"intel_ovms\">Intel OVMS</option>\n </optgroup>\n <optgroup label=\"自定义\">\n <option value=\"custom\">🔧 自定义平台</option>\n </optgroup>\n </select>\n <label>模型</label>\n <input type=\"text\" id=\"model\" value=\"gpt-4o\">\n <label>API Key</label>\n <input type=\"password\" id=\"apiKey\" placeholder=\"输入 API Key\">\n <label>API 地址 <span id=\"urlHint\">(可选)</span></label>\n <input type=\"text\" id=\"customUrl\" placeholder=\"留空使用默认地址\">\n <label>Temperature</label>\n <input type=\"number\" id=\"temperature\" value=\"0.7\" min=\"0\" max=\"2\" step=\"0.1\">\n <label>Max Tokens</label>\n <input type=\"number\" id=\"max_tokens\" value=\"2048\">\n <label style=\"display:flex;align-items:center;gap:8px;margin-top:12px;\">\n <input type=\"checkbox\" id=\"stream\" checked> 流式输出\n </label>\n <div class=\"sessions\">\n <label>对话列表</label>\n <div id=\"sessionList\"></div>\n </div>\n <div class=\"btn-group\">\n <button class=\"btn btn-primary\" onclick=\"newSession()\">新对话</button>\n <button class=\"btn btn-danger\" onclick=\"clearSession()\">清空</button>\n </div>\n <div class=\"btn-group\">\n <button class=\"btn btn-secondary\" onclick=\"exportJSON()\">导出JSON</button>\n <button class=\"btn btn-secondary\" onclick=\"exportMD()\">导出MD</button>\n </div>\n </div>\n <div class=\"main\">\n <div class=\"stats\">\n <span>Token: <strong id=\"tokenCount\">0</strong></span>\n <span>消息: <strong id=\"msgCount\">0</strong></span>\n </div>\n <div class=\"chat-container\" id=\"chat\"></div>\n <div class=\"input-area\">\n <textarea id=\"input\" placeholder=\"输入消息... (Enter发送, Shift+Enter换行)\" onkeydown=\"handleKey(event)\"></textarea>\n <button id=\"sendBtn\" onclick=\"send()\">发送</button>\n </div>\n </div>\n<script>\nconst modelMap = {\n // 国际主流\n openai: 'gpt-4o',\n azure_openai: 'gpt-4o',\n claude: 'claude-sonnet-4-20250514',\n gemini: 'gemini-pro',\n vertex_ai: 'gemini-pro',\n mistral: 'mistral-large-latest',\n groq: 'llama-3.3-70b-versatile',\n together: 'meta-llama/Llama-3.3-70B-Instruct-Turbo',\n fireworks: 'accounts/fireworks/models/llama-v3p3-70b-instruct',\n perplexity: 'llama-3.1-sonar-large-128k-online',\n openrouter: 'openai/gpt-4o',\n grok: 'grok-2-latest',\n hyperbolic: 'meta-llama/Llama-3.3-70B-Instruct',\n nvidia: 'meta/llama-3.1-405b-instruct',\n github_models: 'gpt-4o',\n github_copilot: 'gpt-4o',\n aws_bedrock: 'anthropic.claude-3-sonnet',\n jina: 'jina-embeddings-v2-base-en',\n voyage: 'voyage-large-2',\n poe: 'GPT-4o',\n // 国内平台\n deepseek: 'deepseek-chat',\n zhipu: 'glm-4-plus',\n moonshot: 'moonshot-v1-128k',\n baichuan: 'Baichuan4',\n yi: 'yi-large',\n qwen: 'qwen-plus',\n stepfun: 'step-2-16k',\n minimax: 'abab6.5s-chat',\n doubao: 'doubao-pro-32k',\n hunyuan: 'hunyuan-pro',\n tencent_ti: 'hunyuan-pro',\n baidu_qianfan: 'ernie-4.0-8k',\n tianyi: 'hunyuan-pro',\n wuxinqiong: 'wuxinqiong-chat',\n // API 聚合平台\n siliconflow: 'deepseek-ai/DeepSeek-V3',\n aihubmix: 'gpt-4o',\n ocoolai: 'gpt-4o',\n alaya: 'gpt-4o',\n dmxapi: 'gpt-4o',\n aionly: 'gpt-4o',\n burncloud: 'gpt-4o',\n tokenflux: 'gpt-4o',\n ai302: 'gpt-4o',\n cephalon: 'gpt-4o',\n lanfun: 'gpt-4o',\n ph8: 'gpt-4o',\n ppio: 'gpt-4o',\n qiniu: 'gpt-4o',\n longcat: 'gpt-4o',\n // 本地\n ollama: 'llama3.2',\n lmstudio: 'local-model',\n gpustack: 'local-model',\n intel_ovms: 'local-model'\n};\n\nlet sessions = JSON.parse(localStorage.getItem('sessions') || '[]');\nlet currentSessionId = localStorage.getItem('currentSessionId');\nlet totalTokens = 0;\n\nmarked.setOptions({\n highlight: (code, lang) => {\n if (lang && hljs.getLanguage(lang)) {\n return hljs.highlight(code, { language: lang }).value;\n }\n return hljs.highlightAuto(code).value;\n },\n breaks: true\n});\n\nfunction init() {\n if (sessions.length === 0) newSession();\n else {\n if (!currentSessionId || !sessions.find(s => s.id === currentSessionId)) {\n currentSessionId = sessions[0].id;\n }\n renderSessions();\n loadSession(currentSessionId);\n }\n const theme = localStorage.getItem('theme') || 'dark';\n if (theme === 'light') document.body.classList.add('light-theme');\n document.querySelector('.toggle-theme').textContent = theme === 'light' ? '🌙' : '☀️';\n}\n\nfunction toggleTheme() {\n document.body.classList.toggle('light-theme');\n const isLight = document.body.classList.contains('light-theme');\n localStorage.setItem('theme', isLight ? 'light' : 'dark');\n document.querySelector('.toggle-theme').textContent = isLight ? '🌙' : '☀️';\n}\n\nfunction newSession() {\n const session = {\n id: Date.now().toString(),\n name: '新对话 ' + (sessions.length + 1),\n messages: [],\n tokens: 0,\n provider: document.getElementById('provider').value,\n model: document.getElementById('model').value\n };\n sessions.unshift(session);\n currentSessionId = session.id;\n saveSessions();\n renderSessions();\n renderChat();\n}\n\nfunction saveSessions() {\n localStorage.setItem('sessions', JSON.stringify(sessions));\n localStorage.setItem('currentSessionId', currentSessionId);\n}\n\nfunction getCurrentSession() {\n return sessions.find(s => s.id === currentSessionId);\n}\n\nfunction renderSessions() {\n const list = document.getElementById('sessionList');\n list.innerHTML = sessions.map(s => `\n <div class=\"session-item ${s.id === currentSessionId ? 'active' : ''}\" onclick=\"loadSession('${s.id}')\">\n <span>${s.name}</span>\n <span class=\"delete\" onclick=\"event.stopPropagation();deleteSession('${s.id}')\">×</span>\n </div>\n `).join('');\n}\n\nfunction loadSession(id) {\n currentSessionId = id;\n const session = getCurrentSession();\n if (session) {\n document.getElementById('provider').value = session.provider || 'openai';\n document.getElementById('model').value = session.model || modelMap[session.provider];\n totalTokens = session.tokens || 0;\n }\n saveSessions();\n renderSessions();\n renderChat();\n}\n\nfunction deleteSession(id) {\n sessions = sessions.filter(s => s.id !== id);\n if (sessions.length === 0) newSession();\n else if (currentSessionId === id) currentSessionId = sessions[0].id;\n saveSessions();\n renderSessions();\n renderChat();\n}\n\nfunction clearSession() {\n const session = getCurrentSession();\n if (session) {\n session.messages = [];\n session.tokens = 0;\n totalTokens = 0;\n saveSessions();\n renderChat();\n }\n}\n\nfunction renderChat() {\n const session = getCurrentSession();\n const chat = document.getElementById('chat');\n if (!session) { chat.innerHTML = ''; return; }\n \n chat.innerHTML = session.messages.map(m => {\n const content = m.role === 'assistant' ? marked.parse(m.content) : escapeHtml(m.content);\n return `<div class=\"message ${m.role} ${m.error ? 'error' : ''}\">${content}</div>`;\n }).join('');\n \n document.getElementById('tokenCount').textContent = session.tokens || 0;\n document.getElementById('msgCount').textContent = session.messages.length;\n chat.scrollTop = chat.scrollHeight;\n document.querySelectorAll('.message pre code').forEach(el => hljs.highlightElement(el));\n}\n\nfunction escapeHtml(text) {\n return text.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>');\n}\n\nfunction addMessage(role, content, error = false) {\n const session = getCurrentSession();\n if (!session) return;\n session.messages.push({ role, content, error });\n if (session.messages.length === 1) {\n session.name = content.slice(0, 20) + (content.length > 20 ? '...' : '');\n }\n saveSessions();\n renderChat();\n renderSessions();\n}\n\nfunction updateLastMessage(content) {\n const session = getCurrentSession();\n if (session && session.messages.length > 0) {\n session.messages[session.messages.length - 1].content = content;\n saveSessions();\n renderChat();\n }\n}\n\ndocument.getElementById('provider').onchange = function() {\n document.getElementById('model').value = modelMap[this.value] || '';\n const hint = document.getElementById('urlHint');\n if (this.value === 'custom') {\n hint.textContent = '(必填)';\n hint.style.color = '#e53e3e';\n } else {\n hint.textContent = '(可选)';\n hint.style.color = '';\n }\n const session = getCurrentSession();\n if (session) {\n session.provider = this.value;\n session.model = modelMap[this.value];\n saveSessions();\n }\n};\n\nfunction handleKey(e) {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n send();\n }\n}\n\nasync function send() {\n const input = document.getElementById('input');\n const text = input.value.trim();\n if (!text) return;\n\n input.value = '';\n addMessage('user', text);\n\n const btn = document.getElementById('sendBtn');\n btn.disabled = true;\n\n const session = getCurrentSession();\n session.provider = document.getElementById('provider').value;\n session.model = document.getElementById('model').value;\n\n const payload = {\n provider: session.provider,\n model: session.model,\n messages: session.messages.filter(m => !m.error).map(m => ({ role: m.role, content: m.content })),\n temperature: parseFloat(document.getElementById('temperature').value),\n max_tokens: parseInt(document.getElementById('max_tokens').value),\n stream: document.getElementById('stream').checked,\n custom_url: document.getElementById('customUrl').value || null,\n api_key: document.getElementById('apiKey').value || null\n };\n\n try {\n if (payload.stream) {\n const response = await fetch('/v1/chat/completions', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload)\n });\n \n if (!response.ok) {\n const err = await response.json();\n throw new Error(err.detail || `HTTP ${response.status}`);\n }\n \n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n addMessage('assistant', '');\n let fullText = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const chunk = decoder.decode(value);\n for (const line of chunk.split('\\n')) {\n if (line.startsWith('data: ') && line !== 'data: [DONE]') {\n try {\n const data = JSON.parse(line.slice(6));\n const content = data.choices?.[0]?.delta?.content || '';\n fullText += content;\n updateLastMessage(fullText);\n if (data.usage) {\n session.tokens = (session.tokens || 0) + (data.usage.total_tokens || 0);\n document.getElementById('tokenCount').textContent = session.tokens;\n }\n } catch {}\n }\n }\n }\n } else {\n const response = await fetch('/v1/chat/completions', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload)\n });\n \n if (!response.ok) {\n const err = await response.json();\n throw new Error(err.detail || `HTTP ${response.status}`);\n }\n \n const data = await response.json();\n let content = '';\n if (payload.provider === 'claude') {\n content = data.content?.[0]?.text || JSON.stringify(data);\n session.tokens = (session.tokens || 0) + (data.usage?.input_tokens || 0) + (data.usage?.output_tokens || 0);\n } else if (payload.provider === 'gemini') {\n content = data.candidates?.[0]?.content?.parts?.[0]?.text || JSON.stringify(data);\n } else {\n content = data.choices?.[0]?.message?.content || JSON.stringify(data);\n session.tokens = (session.tokens || 0) + (data.usage?.total_tokens || 0);\n }\n addMessage('assistant', content);\n document.getElementById('tokenCount').textContent = session.tokens;\n }\n saveSessions();\n } catch (e) {\n addMessage('assistant', '❌ 错误: ' + e.message, true);\n }\n btn.disabled = false;\n}\n\nfunction exportJSON() {\n const session = getCurrentSession();\n if (!session) return;\n const blob = new Blob([JSON.stringify(session, null, 2)], { type: 'application/json' });\n downloadBlob(blob, `chat-${session.id}.json`);\n}\n\nfunction exportMD() {\n const session = getCurrentSession();\n if (!session) return;\n let md = `# ${session.name}\\n\\n`;\n session.messages.forEach(m => {\n md += `## ${m.role === 'user' ? '👤 用户' : '🤖 助手'}\\n\\n${m.content}\\n\\n`;\n });\n const blob = new Blob([md], { type: 'text/markdown' });\n downloadBlob(blob, `chat-${session.id}.md`);\n}\n\nfunction downloadBlob(blob, filename) {\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n a.click();\n URL.revokeObjectURL(url);\n}\n\ninit();\n</script>\n</body>\n</html>"}, "f068a797c0ef5eb6059b07da51a4b3c7933c4f3b": {"t": 1785765505.1325016, "n": 22393, "h": "e9aeee6c914dcb04", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>API Gateway Chat</title>\n <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n <style>\n :root {\n --bg-primary: #1a1a2e;\n --bg-secondary: #16213e;\n --bg-chat: #0f0f23;\n --text-primary: #eee;\n --text-secondary: #aaa;\n --accent: #667eea;\n --user-msg: #4a5568;\n --assistant-msg: #2d3748;\n --error: #e53e3e;\n }\n .light-theme {\n --bg-primary: #f5f5f5;\n --bg-secondary: #e0e0e0;\n --bg-chat: #fff;\n --text-primary: #333;\n --text-secondary: #666;\n --user-msg: #e3f2fd;\n --assistant-msg: #f5f5f5;\n }\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: var(--bg-primary);\n color: var(--text-primary);\n height: 100vh;\n display: flex;\n }\n .sidebar {\n width: 280px;\n background: var(--bg-secondary);\n padding: 15px;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n }\n .sidebar h2 { margin-bottom: 15px; font-size: 18px; }\n .sidebar label { margin-top: 12px; font-size: 13px; color: var(--text-secondary); }\n .sidebar select, .sidebar input[type=\"text\"], .sidebar input[type=\"number\"] {\n margin-top: 5px;\n padding: 8px;\n border: none;\n border-radius: 6px;\n background: var(--bg-primary);\n color: var(--text-primary);\n font-size: 13px;\n width: 100%;\n }\n .sessions { margin-top: 15px; flex: 1; overflow-y: auto; }\n .session-item {\n padding: 10px;\n margin: 5px 0;\n background: var(--bg-primary);\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n justify-content: space-between;\n align-items: center;\n font-size: 13px;\n }\n .session-item:hover { opacity: 0.8; }\n .session-item.active { border-left: 3px solid var(--accent); }\n .session-item .delete { color: var(--error); cursor: pointer; padding: 2px 6px; }\n .btn-group { display: flex; gap: 8px; margin-top: 15px; flex-wrap: wrap; }\n .btn {\n padding: 8px 12px;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n font-size: 12px;\n flex: 1;\n min-width: 70px;\n }\n .btn-primary { background: var(--accent); color: #fff; }\n .btn-danger { background: var(--error); color: #fff; }\n .btn-secondary { background: var(--bg-primary); color: var(--text-primary); }\n .main { flex: 1; display: flex; flex-direction: column; padding: 15px; }\n .stats {\n display: flex;\n gap: 15px;\n margin-bottom: 10px;\n font-size: 13px;\n color: var(--text-secondary);\n }\n .chat-container {\n flex: 1;\n overflow-y: auto;\n padding: 15px;\n background: var(--bg-chat);\n border-radius: 12px;\n margin-bottom: 15px;\n }\n .message {\n max-width: 85%;\n padding: 12px 16px;\n margin-bottom: 12px;\n border-radius: 12px;\n line-height: 1.6;\n }\n .message.user { background: var(--user-msg); margin-left: auto; }\n .message.assistant { background: var(--assistant-msg); }\n .message.error { background: var(--error); color: #fff; }\n .message pre { margin: 10px 0; border-radius: 6px; overflow-x: auto; }\n .message code { font-family: 'Consolas', monospace; font-size: 14px; }\n .message p { margin: 8px 0; }\n .message table { border-collapse: collapse; margin: 10px 0; }\n .message th, .message td { border: 1px solid var(--text-secondary); padding: 8px; }\n .input-area { display: flex; gap: 10px; }\n .input-area textarea {\n flex: 1;\n padding: 12px;\n border: none;\n border-radius: 12px;\n background: var(--bg-chat);\n color: var(--text-primary);\n font-size: 14px;\n resize: none;\n height: 60px;\n }\n .input-area button {\n padding: 12px 25px;\n border: none;\n border-radius: 12px;\n background: var(--accent);\n color: #fff;\n font-size: 14px;\n cursor: pointer;\n }\n .input-area button:disabled { opacity: 0.5; cursor: not-allowed; }\n .toggle-theme {\n position: fixed;\n top: 10px;\n right: 10px;\n background: var(--bg-secondary);\n border: none;\n padding: 8px 12px;\n border-radius: 6px;\n cursor: pointer;\n font-size: 16px;\n }\n </style>\n</head>\n<body>\n <button class=\"toggle-theme\" onclick=\"toggleTheme()\">🌙</button>\n <div class=\"sidebar\">\n <h2>⚡ API Gateway</h2>\n <label>平台</label>\n <select id=\"provider\">\n <optgroup label=\"国际主流\">\n <option value=\"openai\">OpenAI</option>\n <option value=\"azure_openai\">Azure OpenAI</option>\n <option value=\"claude\">Anthropic Claude</option>\n <option value=\"gemini\">Google Gemini</option>\n <option value=\"vertex_ai\">Vertex AI</option>\n <option value=\"mistral\">Mistral</option>\n <option value=\"groq\">Groq</option>\n <option value=\"together\">Together</option>\n <option value=\"fireworks\">Fireworks</option>\n <option value=\"perplexity\">Perplexity</option>\n <option value=\"openrouter\">OpenRouter</option>\n <option value=\"grok\">Grok (xAI)</option>\n <option value=\"hyperbolic\">Hyperbolic</option>\n <option value=\"nvidia\">英伟达 NVIDIA</option>\n <option value=\"github_models\">GitHub Models</option>\n <option value=\"github_copilot\">GitHub Copilot</option>\n <option value=\"aws_bedrock\">AWS Bedrock</option>\n <option value=\"jina\">Jina</option>\n <option value=\"voyage\">Voyage AI</option>\n <option value=\"poe\">Poe</option>\n </optgroup>\n <optgroup label=\"国内平台\">\n <option value=\"deepseek\">深度求索 DeepSeek</option>\n <option value=\"zhipu\">智谱 GLM</option>\n <option value=\"moonshot\">月之暗面 Kimi</option>\n <option value=\"baichuan\">百川</option>\n <option value=\"yi\">零一万物</option>\n <option value=\"qwen\">阿里云百炼 Qwen</option>\n <option value=\"stepfun\">阶跃星辰</option>\n <option value=\"minimax\">MiniMax</option>\n <option value=\"doubao\">豆包</option>\n <option value=\"hunyuan\">腾讯混元</option>\n <option value=\"tencent_ti\">腾讯云 TI</option>\n <option value=\"baidu_qianfan\">百度云千帆</option>\n <option value=\"tianyi\">天翼云息壤</option>\n <option value=\"wuxinqiong\">无问芯穹</option>\n </optgroup>\n <optgroup label=\"API 聚合平台\">\n <option value=\"siliconflow\">硅基流动</option>\n <option value=\"aihubmix\">AiHubMix</option>\n <option value=\"ocoolai\">ocoolAI</option>\n <option value=\"alaya\">Alaya NeW</option>\n <option value=\"dmxapi\">DMXAPI</option>\n <option value=\"aionly\">唯一AI (AiOnly)</option>\n <option value=\"burncloud\">BurnCloud</option>\n <option value=\"tokenflux\">TokenFlux</option>\n <option value=\"ai302\">302.AI</option>\n <option value=\"cephalon\">Cephalon</option>\n <option value=\"lanfun\">蓝耘科技</option>\n <option value=\"ph8\">PH8 大模型开放平台</option>\n <option value=\"ppio\">PPIO 派欧云</option>\n <option value=\"qiniu\">七牛云 AI 推理</option>\n <option value=\"longcat\">longcat</option>\n </optgroup>\n <optgroup label=\"本地/自托管\">\n <option value=\"ollama\">Ollama</option>\n <option value=\"lmstudio\">LM Studio</option>\n <option value=\"gpustack\">GPUStack</option>\n <option value=\"intel_ovms\">Intel OVMS</option>\n </optgroup>\n </select>\n <label>模型</label>\n <input type=\"text\" id=\"model\" value=\"gpt-4o\">\n <label>API Key</label>\n <input type=\"password\" id=\"apiKey\" placeholder=\"输入 API Key\">\n <label>自定义 API 地址 (可选)</label>\n <input type=\"text\" id=\"customUrl\" placeholder=\"留空使用默认地址\">\n <label>Temperature</label>\n <input type=\"number\" id=\"temperature\" value=\"0.7\" min=\"0\" max=\"2\" step=\"0.1\">\n <label>Max Tokens</label>\n <input type=\"number\" id=\"max_tokens\" value=\"2048\">\n <label style=\"display:flex;align-items:center;gap:8px;margin-top:12px;\">\n <input type=\"checkbox\" id=\"stream\" checked> 流式输出\n </label>\n <div class=\"sessions\">\n <label>对话列表</label>\n <div id=\"sessionList\"></div>\n </div>\n <div class=\"btn-group\">\n <button class=\"btn btn-primary\" onclick=\"newSession()\">新对话</button>\n <button class=\"btn btn-danger\" onclick=\"clearSession()\">清空</button>\n </div>\n <div class=\"btn-group\">\n <button class=\"btn btn-secondary\" onclick=\"exportJSON()\">导出JSON</button>\n <button class=\"btn btn-secondary\" onclick=\"exportMD()\">导出MD</button>\n </div>\n </div>\n <div class=\"main\">\n <div class=\"stats\">\n <span>Token: <strong id=\"tokenCount\">0</strong></span>\n <span>消息: <strong id=\"msgCount\">0</strong></span>\n </div>\n <div class=\"chat-container\" id=\"chat\"></div>\n <div class=\"input-area\">\n <textarea id=\"input\" placeholder=\"输入消息... (Enter发送, Shift+Enter换行)\" onkeydown=\"handleKey(event)\"></textarea>\n <button id=\"sendBtn\" onclick=\"send()\">发送</button>\n </div>\n </div>\n<script>\nconst modelMap = {\n // 国际主流\n openai: 'gpt-4o',\n azure_openai: 'gpt-4o',\n claude: 'claude-sonnet-4-20250514',\n gemini: 'gemini-pro',\n vertex_ai: 'gemini-pro',\n mistral: 'mistral-large-latest',\n groq: 'llama-3.3-70b-versatile',\n together: 'meta-llama/Llama-3.3-70B-Instruct-Turbo',\n fireworks: 'accounts/fireworks/models/llama-v3p3-70b-instruct',\n perplexity: 'llama-3.1-sonar-large-128k-online',\n openrouter: 'openai/gpt-4o',\n grok: 'grok-2-latest',\n hyperbolic: 'meta-llama/Llama-3.3-70B-Instruct',\n nvidia: 'meta/llama-3.1-405b-instruct',\n github_models: 'gpt-4o',\n github_copilot: 'gpt-4o',\n aws_bedrock: 'anthropic.claude-3-sonnet',\n jina: 'jina-embeddings-v2-base-en',\n voyage: 'voyage-large-2',\n poe: 'GPT-4o',\n // 国内平台\n deepseek: 'deepseek-chat',\n zhipu: 'glm-4-plus',\n moonshot: 'moonshot-v1-128k',\n baichuan: 'Baichuan4',\n yi: 'yi-large',\n qwen: 'qwen-plus',\n stepfun: 'step-2-16k',\n minimax: 'abab6.5s-chat',\n doubao: 'doubao-pro-32k',\n hunyuan: 'hunyuan-pro',\n tencent_ti: 'hunyuan-pro',\n baidu_qianfan: 'ernie-4.0-8k',\n tianyi: 'hunyuan-pro',\n wuxinqiong: 'wuxinqiong-chat',\n // API 聚合平台\n siliconflow: 'deepseek-ai/DeepSeek-V3',\n aihubmix: 'gpt-4o',\n ocoolai: 'gpt-4o',\n alaya: 'gpt-4o',\n dmxapi: 'gpt-4o',\n aionly: 'gpt-4o',\n burncloud: 'gpt-4o',\n tokenflux: 'gpt-4o',\n ai302: 'gpt-4o',\n cephalon: 'gpt-4o',\n lanfun: 'gpt-4o',\n ph8: 'gpt-4o',\n ppio: 'gpt-4o',\n qiniu: 'gpt-4o',\n longcat: 'gpt-4o',\n // 本地\n ollama: 'llama3.2',\n lmstudio: 'local-model',\n gpustack: 'local-model',\n intel_ovms: 'local-model'\n};\n\nlet sessions = JSON.parse(localStorage.getItem('sessions') || '[]');\nlet currentSessionId = localStorage.getItem('currentSessionId');\nlet totalTokens = 0;\n\nmarked.setOptions({\n highlight: (code, lang) => {\n if (lang && hljs.getLanguage(lang)) {\n return hljs.highlight(code, { language: lang }).value;\n }\n return hljs.highlightAuto(code).value;\n },\n breaks: true\n});\n\nfunction init() {\n if (sessions.length === 0) newSession();\n else {\n if (!currentSessionId || !sessions.find(s => s.id === currentSessionId)) {\n currentSessionId = sessions[0].id;\n }\n renderSessions();\n loadSession(currentSessionId);\n }\n const theme = localStorage.getItem('theme') || 'dark';\n if (theme === 'light') document.body.classList.add('light-theme');\n document.querySelector('.toggle-theme').textContent = theme === 'light' ? '🌙' : '☀️';\n}\n\nfunction toggleTheme() {\n document.body.classList.toggle('light-theme');\n const isLight = document.body.classList.contains('light-theme');\n localStorage.setItem('theme', isLight ? 'light' : 'dark');\n document.querySelector('.toggle-theme').textContent = isLight ? '🌙' : '☀️';\n}\n\nfunction newSession() {\n const session = {\n id: Date.now().toString(),\n name: '新对话 ' + (sessions.length + 1),\n messages: [],\n tokens: 0,\n provider: document.getElementById('provider').value,\n model: document.getElementById('model').value\n };\n sessions.unshift(session);\n currentSessionId = session.id;\n saveSessions();\n renderSessions();\n renderChat();\n}\n\nfunction saveSessions() {\n localStorage.setItem('sessions', JSON.stringify(sessions));\n localStorage.setItem('currentSessionId', currentSessionId);\n}\n\nfunction getCurrentSession() {\n return sessions.find(s => s.id === currentSessionId);\n}\n\nfunction renderSessions() {\n const list = document.getElementById('sessionList');\n list.innerHTML = sessions.map(s => `\n <div class=\"session-item ${s.id === currentSessionId ? 'active' : ''}\" onclick=\"loadSession('${s.id}')\">\n <span>${s.name}</span>\n <span class=\"delete\" onclick=\"event.stopPropagation();deleteSession('${s.id}')\">×</span>\n </div>\n `).join('');\n}\n\nfunction loadSession(id) {\n currentSessionId = id;\n const session = getCurrentSession();\n if (session) {\n document.getElementById('provider').value = session.provider || 'openai';\n document.getElementById('model').value = session.model || modelMap[session.provider];\n totalTokens = session.tokens || 0;\n }\n saveSessions();\n renderSessions();\n renderChat();\n}\n\nfunction deleteSession(id) {\n sessions = sessions.filter(s => s.id !== id);\n if (sessions.length === 0) newSession();\n else if (currentSessionId === id) currentSessionId = sessions[0].id;\n saveSessions();\n renderSessions();\n renderChat();\n}\n\nfunction clearSession() {\n const session = getCurrentSession();\n if (session) {\n session.messages = [];\n session.tokens = 0;\n totalTokens = 0;\n saveSessions();\n renderChat();\n }\n}\n\nfunction renderChat() {\n const session = getCurrentSession();\n const chat = document.getElementById('chat');\n if (!session) { chat.innerHTML = ''; return; }\n \n chat.innerHTML = session.messages.map(m => {\n const content = m.role === 'assistant' ? marked.parse(m.content) : escapeHtml(m.content);\n return `<div class=\"message ${m.role} ${m.error ? 'error' : ''}\">${content}</div>`;\n }).join('');\n \n document.getElementById('tokenCount').textContent = session.tokens || 0;\n document.getElementById('msgCount').textContent = session.messages.length;\n chat.scrollTop = chat.scrollHeight;\n document.querySelectorAll('.message pre code').forEach(el => hljs.highlightElement(el));\n}\n\nfunction escapeHtml(text) {\n return text.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>');\n}\n\nfunction addMessage(role, content, error = false) {\n const session = getCurrentSession();\n if (!session) return;\n session.messages.push({ role, content, error });\n if (session.messages.length === 1) {\n session.name = content.slice(0, 20) + (content.length > 20 ? '...' : '');\n }\n saveSessions();\n renderChat();\n renderSessions();\n}\n\nfunction updateLastMessage(content) {\n const session = getCurrentSession();\n if (session && session.messages.length > 0) {\n session.messages[session.messages.length - 1].content = content;\n saveSessions();\n renderChat();\n }\n}\n\ndocument.getElementById('provider').onchange = function() {\n document.getElementById('model').value = modelMap[this.value] || '';\n const session = getCurrentSession();\n if (session) {\n session.provider = this.value;\n session.model = modelMap[this.value];\n saveSessions();\n }\n};\n\nfunction handleKey(e) {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n send();\n }\n}\n\nasync function send() {\n const input = document.getElementById('input');\n const text = input.value.trim();\n if (!text) return;\n\n input.value = '';\n addMessage('user', text);\n\n const btn = document.getElementById('sendBtn');\n btn.disabled = true;\n\n const session = getCurrentSession();\n session.provider = document.getElementById('provider').value;\n session.model = document.getElementById('model').value;\n\n const payload = {\n provider: session.provider,\n model: session.model,\n messages: session.messages.filter(m => !m.error).map(m => ({ role: m.role, content: m.content })),\n temperature: parseFloat(document.getElementById('temperature').value),\n max_tokens: parseInt(document.getElementById('max_tokens').value),\n stream: document.getElementById('stream').checked,\n custom_url: document.getElementById('customUrl').value || null,\n api_key: document.getElementById('apiKey').value || null\n };\n\n try {\n if (payload.stream) {\n const response = await fetch('/v1/chat/completions', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload)\n });\n \n if (!response.ok) {\n const err = await response.json();\n throw new Error(err.detail || `HTTP ${response.status}`);\n }\n \n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n addMessage('assistant', '');\n let fullText = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const chunk = decoder.decode(value);\n for (const line of chunk.split('\\n')) {\n if (line.startsWith('data: ') && line !== 'data: [DONE]') {\n try {\n const data = JSON.parse(line.slice(6));\n const content = data.choices?.[0]?.delta?.content || '';\n fullText += content;\n updateLastMessage(fullText);\n if (data.usage) {\n session.tokens = (session.tokens || 0) + (data.usage.total_tokens || 0);\n document.getElementById('tokenCount').textContent = session.tokens;\n }\n } catch {}\n }\n }\n }\n } else {\n const response = await fetch('/v1/chat/completions', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload)\n });\n \n if (!response.ok) {\n const err = await response.json();\n throw new Error(err.detail || `HTTP ${response.status}`);\n }\n \n const data = await response.json();\n let content = '';\n if (payload.provider === 'claude') {\n content = data.content?.[0]?.text || JSON.stringify(data);\n session.tokens = (session.tokens || 0) + (data.usage?.input_tokens || 0) + (data.usage?.output_tokens || 0);\n } else if (payload.provider === 'gemini') {\n content = data.candidates?.[0]?.content?.parts?.[0]?.text || JSON.stringify(data);\n } else {\n content = data.choices?.[0]?.message?.content || JSON.stringify(data);\n session.tokens = (session.tokens || 0) + (data.usage?.total_tokens || 0);\n }\n addMessage('assistant', content);\n document.getElementById('tokenCount').textContent = session.tokens;\n }\n saveSessions();\n } catch (e) {\n addMessage('assistant', '❌ 错误: ' + e.message, true);\n }\n btn.disabled = false;\n}\n\nfunction exportJSON() {\n const session = getCurrentSession();\n if (!session) return;\n const blob = new Blob([JSON.stringify(session, null, 2)], { type: 'application/json' });\n downloadBlob(blob, `chat-${session.id}.json`);\n}\n\nfunction exportMD() {\n const session = getCurrentSession();\n if (!session) return;\n let md = `# ${session.name}\\n\\n`;\n session.messages.forEach(m => {\n md += `## ${m.role === 'user' ? '👤 用户' : '🤖 助手'}\\n\\n${m.content}\\n\\n`;\n });\n const blob = new Blob([md], { type: 'text/markdown' });\n downloadBlob(blob, `chat-${session.id}.md`);\n}\n\nfunction downloadBlob(blob, filename) {\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n a.click();\n URL.revokeObjectURL(url);\n}\n\ninit();\n</script>\n</body>\n</html>"}, "cec109b3a8fe4b8f0765439dc718886c42afedd9": {"t": 1785765506.611933, "n": 22227, "h": "bbdfc3213cfcffe5", "c": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>API Gateway Chat</title>\n <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\">\n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js\"></script>\n <style>\n :root {\n --bg-primary: #1a1a2e;\n --bg-secondary: #16213e;\n --bg-chat: #0f0f23;\n --text-primary: #eee;\n --text-secondary: #aaa;\n --accent: #667eea;\n --user-msg: #4a5568;\n --assistant-msg: #2d3748;\n --error: #e53e3e;\n }\n .light-theme {\n --bg-primary: #f5f5f5;\n --bg-secondary: #e0e0e0;\n --bg-chat: #fff;\n --text-primary: #333;\n --text-secondary: #666;\n --user-msg: #e3f2fd;\n --assistant-msg: #f5f5f5;\n }\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: var(--bg-primary);\n color: var(--text-primary);\n height: 100vh;\n display: flex;\n }\n .sidebar {\n width: 280px;\n background: var(--bg-secondary);\n padding: 15px;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n }\n .sidebar h2 { margin-bottom: 15px; font-size: 18px; }\n .sidebar label { margin-top: 12px; font-size: 13px; color: var(--text-secondary); }\n .sidebar select, .sidebar input[type=\"text\"], .sidebar input[type=\"number\"] {\n margin-top: 5px;\n padding: 8px;\n border: none;\n border-radius: 6px;\n background: var(--bg-primary);\n color: var(--text-primary);\n font-size: 13px;\n width: 100%;\n }\n .sessions { margin-top: 15px; flex: 1; overflow-y: auto; }\n .session-item {\n padding: 10px;\n margin: 5px 0;\n background: var(--bg-primary);\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n justify-content: space-between;\n align-items: center;\n font-size: 13px;\n }\n .session-item:hover { opacity: 0.8; }\n .session-item.active { border-left: 3px solid var(--accent); }\n .session-item .delete { color: var(--error); cursor: pointer; padding: 2px 6px; }\n .btn-group { display: flex; gap: 8px; margin-top: 15px; flex-wrap: wrap; }\n .btn {\n padding: 8px 12px;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n font-size: 12px;\n flex: 1;\n min-width: 70px;\n }\n .btn-primary { background: var(--accent); color: #fff; }\n .btn-danger { background: var(--error); color: #fff; }\n .btn-secondary { background: var(--bg-primary); color: var(--text-primary); }\n .main { flex: 1; display: flex; flex-direction: column; padding: 15px; }\n .stats {\n display: flex;\n gap: 15px;\n margin-bottom: 10px;\n font-size: 13px;\n color: var(--text-secondary);\n }\n .chat-container {\n flex: 1;\n overflow-y: auto;\n padding: 15px;\n background: var(--bg-chat);\n border-radius: 12px;\n margin-bottom: 15px;\n }\n .message {\n max-width: 85%;\n padding: 12px 16px;\n margin-bottom: 12px;\n border-radius: 12px;\n line-height: 1.6;\n }\n .message.user { background: var(--user-msg); margin-left: auto; }\n .message.assistant { background: var(--assistant-msg); }\n .message.error { background: var(--error); color: #fff; }\n .message pre { margin: 10px 0; border-radius: 6px; overflow-x: auto; }\n .message code { font-family: 'Consolas', monospace; font-size: 14px; }\n .message p { margin: 8px 0; }\n .message table { border-collapse: collapse; margin: 10px 0; }\n .message th, .message td { border: 1px solid var(--text-secondary); padding: 8px; }\n .input-area { display: flex; gap: 10px; }\n .input-area textarea {\n flex: 1;\n padding: 12px;\n border: none;\n border-radius: 12px;\n background: var(--bg-chat);\n color: var(--text-primary);\n font-size: 14px;\n resize: none;\n height: 60px;\n }\n .input-area button {\n padding: 12px 25px;\n border: none;\n border-radius: 12px;\n background: var(--accent);\n color: #fff;\n font-size: 14px;\n cursor: pointer;\n }\n .input-area button:disabled { opacity: 0.5; cursor: not-allowed; }\n .toggle-theme {\n position: fixed;\n top: 10px;\n right: 10px;\n background: var(--bg-secondary);\n border: none;\n padding: 8px 12px;\n border-radius: 6px;\n cursor: pointer;\n font-size: 16px;\n }\n </style>\n</head>\n<body>\n <button class=\"toggle-theme\" onclick=\"toggleTheme()\">🌙</button>\n <div class=\"sidebar\">\n <h2>⚡ API Gateway</h2>\n <label>平台</label>\n <select id=\"provider\">\n <optgroup label=\"国际主流\">\n <option value=\"openai\">OpenAI</option>\n <option value=\"azure_openai\">Azure OpenAI</option>\n <option value=\"claude\">Anthropic Claude</option>\n <option value=\"gemini\">Google Gemini</option>\n <option value=\"vertex_ai\">Vertex AI</option>\n <option value=\"mistral\">Mistral</option>\n <option value=\"groq\">Groq</option>\n <option value=\"together\">Together</option>\n <option value=\"fireworks\">Fireworks</option>\n <option value=\"perplexity\">Perplexity</option>\n <option value=\"openrouter\">OpenRouter</option>\n <option value=\"grok\">Grok (xAI)</option>\n <option value=\"hyperbolic\">Hyperbolic</option>\n <option value=\"nvidia\">英伟达 NVIDIA</option>\n <option value=\"github_models\">GitHub Models</option>\n <option value=\"github_copilot\">GitHub Copilot</option>\n <option value=\"aws_bedrock\">AWS Bedrock</option>\n <option value=\"jina\">Jina</option>\n <option value=\"voyage\">Voyage AI</option>\n <option value=\"poe\">Poe</option>\n </optgroup>\n <optgroup label=\"国内平台\">\n <option value=\"deepseek\">深度求索 DeepSeek</option>\n <option value=\"zhipu\">智谱 GLM</option>\n <option value=\"moonshot\">月之暗面 Kimi</option>\n <option value=\"baichuan\">百川</option>\n <option value=\"yi\">零一万物</option>\n <option value=\"qwen\">阿里云百炼 Qwen</option>\n <option value=\"stepfun\">阶跃星辰</option>\n <option value=\"minimax\">MiniMax</option>\n <option value=\"doubao\">豆包</option>\n <option value=\"hunyuan\">腾讯混元</option>\n <option value=\"tencent_ti\">腾讯云 TI</option>\n <option value=\"baidu_qianfan\">百度云千帆</option>\n <option value=\"tianyi\">天翼云息壤</option>\n <option value=\"wuxinqiong\">无问芯穹</option>\n </optgroup>\n <optgroup label=\"API 聚合平台\">\n <option value=\"siliconflow\">硅基流动</option>\n <option value=\"aihubmix\">AiHubMix</option>\n <option value=\"ocoolai\">ocoolAI</option>\n <option value=\"alaya\">Alaya NeW</option>\n <option value=\"dmxapi\">DMXAPI</option>\n <option value=\"aionly\">唯一AI (AiOnly)</option>\n <option value=\"burncloud\">BurnCloud</option>\n <option value=\"tokenflux\">TokenFlux</option>\n <option value=\"ai302\">302.AI</option>\n <option value=\"cephalon\">Cephalon</option>\n <option value=\"lanfun\">蓝耘科技</option>\n <option value=\"ph8\">PH8 大模型开放平台</option>\n <option value=\"ppio\">PPIO 派欧云</option>\n <option value=\"qiniu\">七牛云 AI 推理</option>\n <option value=\"longcat\">longcat</option>\n </optgroup>\n <optgroup label=\"本地/自托管\">\n <option value=\"ollama\">Ollama</option>\n <option value=\"lmstudio\">LM Studio</option>\n <option value=\"gpustack\">GPUStack</option>\n <option value=\"intel_ovms\">Intel OVMS</option>\n </optgroup>\n </select>\n <label>模型</label>\n <input type=\"text\" id=\"model\" value=\"gpt-4o\">\n <label>自定义 API 地址 (可选)</label>\n <input type=\"text\" id=\"customUrl\" placeholder=\"留空使用默认地址\">\n <label>Temperature</label>\n <input type=\"number\" id=\"temperature\" value=\"0.7\" min=\"0\" max=\"2\" step=\"0.1\">\n <label>Max Tokens</label>\n <input type=\"number\" id=\"max_tokens\" value=\"2048\">\n <label style=\"display:flex;align-items:center;gap:8px;margin-top:12px;\">\n <input type=\"checkbox\" id=\"stream\" checked> 流式输出\n </label>\n <div class=\"sessions\">\n <label>对话列表</label>\n <div id=\"sessionList\"></div>\n </div>\n <div class=\"btn-group\">\n <button class=\"btn btn-primary\" onclick=\"newSession()\">新对话</button>\n <button class=\"btn btn-danger\" onclick=\"clearSession()\">清空</button>\n </div>\n <div class=\"btn-group\">\n <button class=\"btn btn-secondary\" onclick=\"exportJSON()\">导出JSON</button>\n <button class=\"btn btn-secondary\" onclick=\"exportMD()\">导出MD</button>\n </div>\n </div>\n <div class=\"main\">\n <div class=\"stats\">\n <span>Token: <strong id=\"tokenCount\">0</strong></span>\n <span>消息: <strong id=\"msgCount\">0</strong></span>\n </div>\n <div class=\"chat-container\" id=\"chat\"></div>\n <div class=\"input-area\">\n <textarea id=\"input\" placeholder=\"输入消息... (Enter发送, Shift+Enter换行)\" onkeydown=\"handleKey(event)\"></textarea>\n <button id=\"sendBtn\" onclick=\"send()\">发送</button>\n </div>\n </div>\n<script>\nconst modelMap = {\n // 国际主流\n openai: 'gpt-4o',\n azure_openai: 'gpt-4o',\n claude: 'claude-sonnet-4-20250514',\n gemini: 'gemini-pro',\n vertex_ai: 'gemini-pro',\n mistral: 'mistral-large-latest',\n groq: 'llama-3.3-70b-versatile',\n together: 'meta-llama/Llama-3.3-70B-Instruct-Turbo',\n fireworks: 'accounts/fireworks/models/llama-v3p3-70b-instruct',\n perplexity: 'llama-3.1-sonar-large-128k-online',\n openrouter: 'openai/gpt-4o',\n grok: 'grok-2-latest',\n hyperbolic: 'meta-llama/Llama-3.3-70B-Instruct',\n nvidia: 'meta/llama-3.1-405b-instruct',\n github_models: 'gpt-4o',\n github_copilot: 'gpt-4o',\n aws_bedrock: 'anthropic.claude-3-sonnet',\n jina: 'jina-embeddings-v2-base-en',\n voyage: 'voyage-large-2',\n poe: 'GPT-4o',\n // 国内平台\n deepseek: 'deepseek-chat',\n zhipu: 'glm-4-plus',\n moonshot: 'moonshot-v1-128k',\n baichuan: 'Baichuan4',\n yi: 'yi-large',\n qwen: 'qwen-plus',\n stepfun: 'step-2-16k',\n minimax: 'abab6.5s-chat',\n doubao: 'doubao-pro-32k',\n hunyuan: 'hunyuan-pro',\n tencent_ti: 'hunyuan-pro',\n baidu_qianfan: 'ernie-4.0-8k',\n tianyi: 'hunyuan-pro',\n wuxinqiong: 'wuxinqiong-chat',\n // API 聚合平台\n siliconflow: 'deepseek-ai/DeepSeek-V3',\n aihubmix: 'gpt-4o',\n ocoolai: 'gpt-4o',\n alaya: 'gpt-4o',\n dmxapi: 'gpt-4o',\n aionly: 'gpt-4o',\n burncloud: 'gpt-4o',\n tokenflux: 'gpt-4o',\n ai302: 'gpt-4o',\n cephalon: 'gpt-4o',\n lanfun: 'gpt-4o',\n ph8: 'gpt-4o',\n ppio: 'gpt-4o',\n qiniu: 'gpt-4o',\n longcat: 'gpt-4o',\n // 本地\n ollama: 'llama3.2',\n lmstudio: 'local-model',\n gpustack: 'local-model',\n intel_ovms: 'local-model'\n};\n\nlet sessions = JSON.parse(localStorage.getItem('sessions') || '[]');\nlet currentSessionId = localStorage.getItem('currentSessionId');\nlet totalTokens = 0;\n\nmarked.setOptions({\n highlight: (code, lang) => {\n if (lang && hljs.getLanguage(lang)) {\n return hljs.highlight(code, { language: lang }).value;\n }\n return hljs.highlightAuto(code).value;\n },\n breaks: true\n});\n\nfunction init() {\n if (sessions.length === 0) newSession();\n else {\n if (!currentSessionId || !sessions.find(s => s.id === currentSessionId)) {\n currentSessionId = sessions[0].id;\n }\n renderSessions();\n loadSession(currentSessionId);\n }\n const theme = localStorage.getItem('theme') || 'dark';\n if (theme === 'light') document.body.classList.add('light-theme');\n document.querySelector('.toggle-theme').textContent = theme === 'light' ? '🌙' : '☀️';\n}\n\nfunction toggleTheme() {\n document.body.classList.toggle('light-theme');\n const isLight = document.body.classList.contains('light-theme');\n localStorage.setItem('theme', isLight ? 'light' : 'dark');\n document.querySelector('.toggle-theme').textContent = isLight ? '🌙' : '☀️';\n}\n\nfunction newSession() {\n const session = {\n id: Date.now().toString(),\n name: '新对话 ' + (sessions.length + 1),\n messages: [],\n tokens: 0,\n provider: document.getElementById('provider').value,\n model: document.getElementById('model').value\n };\n sessions.unshift(session);\n currentSessionId = session.id;\n saveSessions();\n renderSessions();\n renderChat();\n}\n\nfunction saveSessions() {\n localStorage.setItem('sessions', JSON.stringify(sessions));\n localStorage.setItem('currentSessionId', currentSessionId);\n}\n\nfunction getCurrentSession() {\n return sessions.find(s => s.id === currentSessionId);\n}\n\nfunction renderSessions() {\n const list = document.getElementById('sessionList');\n list.innerHTML = sessions.map(s => `\n <div class=\"session-item ${s.id === currentSessionId ? 'active' : ''}\" onclick=\"loadSession('${s.id}')\">\n <span>${s.name}</span>\n <span class=\"delete\" onclick=\"event.stopPropagation();deleteSession('${s.id}')\">×</span>\n </div>\n `).join('');\n}\n\nfunction loadSession(id) {\n currentSessionId = id;\n const session = getCurrentSession();\n if (session) {\n document.getElementById('provider').value = session.provider || 'openai';\n document.getElementById('model').value = session.model || modelMap[session.provider];\n totalTokens = session.tokens || 0;\n }\n saveSessions();\n renderSessions();\n renderChat();\n}\n\nfunction deleteSession(id) {\n sessions = sessions.filter(s => s.id !== id);\n if (sessions.length === 0) newSession();\n else if (currentSessionId === id) currentSessionId = sessions[0].id;\n saveSessions();\n renderSessions();\n renderChat();\n}\n\nfunction clearSession() {\n const session = getCurrentSession();\n if (session) {\n session.messages = [];\n session.tokens = 0;\n totalTokens = 0;\n saveSessions();\n renderChat();\n }\n}\n\nfunction renderChat() {\n const session = getCurrentSession();\n const chat = document.getElementById('chat');\n if (!session) { chat.innerHTML = ''; return; }\n \n chat.innerHTML = session.messages.map(m => {\n const content = m.role === 'assistant' ? marked.parse(m.content) : escapeHtml(m.content);\n return `<div class=\"message ${m.role} ${m.error ? 'error' : ''}\">${content}</div>`;\n }).join('');\n \n document.getElementById('tokenCount').textContent = session.tokens || 0;\n document.getElementById('msgCount').textContent = session.messages.length;\n chat.scrollTop = chat.scrollHeight;\n document.querySelectorAll('.message pre code').forEach(el => hljs.highlightElement(el));\n}\n\nfunction escapeHtml(text) {\n return text.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\\n/g,'<br>');\n}\n\nfunction addMessage(role, content, error = false) {\n const session = getCurrentSession();\n if (!session) return;\n session.messages.push({ role, content, error });\n if (session.messages.length === 1) {\n session.name = content.slice(0, 20) + (content.length > 20 ? '...' : '');\n }\n saveSessions();\n renderChat();\n renderSessions();\n}\n\nfunction updateLastMessage(content) {\n const session = getCurrentSession();\n if (session && session.messages.length > 0) {\n session.messages[session.messages.length - 1].content = content;\n saveSessions();\n renderChat();\n }\n}\n\ndocument.getElementById('provider').onchange = function() {\n document.getElementById('model').value = modelMap[this.value] || '';\n const session = getCurrentSession();\n if (session) {\n session.provider = this.value;\n session.model = modelMap[this.value];\n saveSessions();\n }\n};\n\nfunction handleKey(e) {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n send();\n }\n}\n\nasync function send() {\n const input = document.getElementById('input');\n const text = input.value.trim();\n if (!text) return;\n\n input.value = '';\n addMessage('user', text);\n\n const btn = document.getElementById('sendBtn');\n btn.disabled = true;\n\n const session = getCurrentSession();\n session.provider = document.getElementById('provider').value;\n session.model = document.getElementById('model').value;\n\n const payload = {\n provider: session.provider,\n model: session.model,\n messages: session.messages.filter(m => !m.error).map(m => ({ role: m.role, content: m.content })),\n temperature: parseFloat(document.getElementById('temperature').value),\n max_tokens: parseInt(document.getElementById('max_tokens').value),\n stream: document.getElementById('stream').checked,\n custom_url: document.getElementById('customUrl').value || null\n };\n\n try {\n if (payload.stream) {\n const response = await fetch('/v1/chat/completions', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload)\n });\n \n if (!response.ok) {\n const err = await response.json();\n throw new Error(err.detail || `HTTP ${response.status}`);\n }\n \n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n addMessage('assistant', '');\n let fullText = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const chunk = decoder.decode(value);\n for (const line of chunk.split('\\n')) {\n if (line.startsWith('data: ') && line !== 'data: [DONE]') {\n try {\n const data = JSON.parse(line.slice(6));\n const content = data.choices?.[0]?.delta?.content || '';\n fullText += content;\n updateLastMessage(fullText);\n if (data.usage) {\n session.tokens = (session.tokens || 0) + (data.usage.total_tokens || 0);\n document.getElementById('tokenCount').textContent = session.tokens;\n }\n } catch {}\n }\n }\n }\n } else {\n const response = await fetch('/v1/chat/completions', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload)\n });\n \n if (!response.ok) {\n const err = await response.json();\n throw new Error(err.detail || `HTTP ${response.status}`);\n }\n \n const data = await response.json();\n let content = '';\n if (payload.provider === 'claude') {\n content = data.content?.[0]?.text || JSON.stringify(data);\n session.tokens = (session.tokens || 0) + (data.usage?.input_tokens || 0) + (data.usage?.output_tokens || 0);\n } else if (payload.provider === 'gemini') {\n content = data.candidates?.[0]?.content?.parts?.[0]?.text || JSON.stringify(data);\n } else {\n content = data.choices?.[0]?.message?.content || JSON.stringify(data);\n session.tokens = (session.tokens || 0) + (data.usage?.total_tokens || 0);\n }\n addMessage('assistant', content);\n document.getElementById('tokenCount').textContent = session.tokens;\n }\n saveSessions();\n } catch (e) {\n addMessage('assistant', '❌ 错误: ' + e.message, true);\n }\n btn.disabled = false;\n}\n\nfunction exportJSON() {\n const session = getCurrentSession();\n if (!session) return;\n const blob = new Blob([JSON.stringify(session, null, 2)], { type: 'application/json' });\n downloadBlob(blob, `chat-${session.id}.json`);\n}\n\nfunction exportMD() {\n const session = getCurrentSession();\n if (!session) return;\n let md = `# ${session.name}\\n\\n`;\n session.messages.forEach(m => {\n md += `## ${m.role === 'user' ? '👤 用户' : '🤖 助手'}\\n\\n${m.content}\\n\\n`;\n });\n const blob = new Blob([md], { type: 'text/markdown' });\n downloadBlob(blob, `chat-${session.id}.md`);\n}\n\nfunction downloadBlob(blob, filename) {\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n a.click();\n URL.revokeObjectURL(url);\n}\n\ninit();\n</script>\n</body>\n</html>"}}}}