1 line
5.4 MiB
Plaintext
1 line
5.4 MiB
Plaintext
{"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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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:'\\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&¤tIdx<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&¤tChatId){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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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:'\\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&¤tIdx<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&¤tChatId){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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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:'\\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&¤tIdx<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&¤tChatId){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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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:'\\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&¤tIdx<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&¤tChatId){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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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:'\\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&¤tIdx<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&¤tChatId){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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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:'\\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&¤tIdx<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&¤tChatId){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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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:'\\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&¤tIdx<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&¤tChatId){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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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:'\\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&¤tIdx<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&¤tChatId){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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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:'\\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&¤tIdx<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&¤tChatId){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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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:'\\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&¤tIdx<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&¤tChatId){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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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:'\\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&¤tIdx<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&¤tChatId){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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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:'\\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&¤tIdx<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&¤tChatId){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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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:'\\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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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+'\\')\">×</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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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/* 正则表达式: /.*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=\"请将以下内容翻译成中文: {{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,'&').replace(/</g,'<').replace(/>/g,'>').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,'&').replace(/</g,'<').replace(/>/g,'>').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,'&').replace(/</g,'<').replace(/>/g,'>').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,'&').replace(/</g,'<').replace(/>/g,'>').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>"}}}} |