diff --git a/docs/index.html b/docs/index.html index 91ec9433..e966da1b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,9 +1,9 @@ - + - + @@ -19,18 +19,18 @@ --r:14px;--rs:8px; --ls-w:260px;--rs-w:360px; } -html,body{height:100%;background:var(--bg);color:var(--text);font-family:'PingFang SC','Microsoft YaHei','Segoe UI',sans-serif;font-size:15px;line-height:1.6} +html,body{height:100%;background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei','Segoe UI',sans-serif;font-size:15px;line-height:1.6;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent;overscroll-behavior:none} /* ─── SETUP ─── */ -#setup{position:fixed;inset:0;z-index:1000;background:var(--bg);display:flex;align-items:center;justify-content:center;padding:20px} -.sc{background:var(--s1);border:1px solid var(--border);border-radius:20px;padding:40px;width:100%;max-width:460px;box-shadow:0 25px 60px rgba(0,0,0,.5)} +#setup{position:fixed;inset:0;z-index:1000;background:var(--bg);display:flex;align-items:center;justify-content:center;padding:20px;padding:max(20px,env(safe-area-inset-top)) max(20px,env(safe-area-inset-right)) max(20px,env(safe-area-inset-bottom)) max(20px,env(safe-area-inset-left));overflow-y:auto;-webkit-overflow-scrolling:touch} +.sc{background:var(--s1);border:1px solid var(--border);border-radius:20px;padding:40px;width:100%;max-width:460px;box-shadow:0 25px 60px rgba(0,0,0,.5);margin:auto} .sc-logo{font-size:52px;text-align:center;margin-bottom:14px} .sc h1{font-size:22px;text-align:center;margin-bottom:6px} .sc .sub{color:var(--dim);text-align:center;font-size:13px;margin-bottom:22px} .sc-sec{background:rgba(52,211,153,.08);border:1px solid rgba(52,211,153,.3);border-radius:var(--rs);padding:9px 12px;font-size:12px;color:var(--ok);margin-bottom:20px;text-align:center} .fg{margin-bottom:16px} .fg label{display:block;font-size:11px;color:var(--dim);margin-bottom:6px;font-weight:600;text-transform:uppercase;letter-spacing:.05em} -.fg input,.fg select{width:100%;padding:10px 12px;background:var(--s2);border:1px solid var(--border);border-radius:var(--rs);color:var(--text);font-size:14px;font-family:inherit;outline:none;transition:border-color .2s} +.fg input,.fg select{width:100%;padding:10px 12px;background:var(--s2);border:1px solid var(--border);border-radius:var(--rs);color:var(--text);font-size:16px;font-family:inherit;outline:none;transition:border-color .2s} .fg input:focus,.fg select:focus{border-color:var(--accent)} .fg select option{background:var(--s2)} .fg small{display:block;color:var(--dim);font-size:11px;margin-top:5px} @@ -47,7 +47,7 @@ html,body{height:100%;background:var(--bg);color:var(--text);font-family:'PingFa #id-preview{display:none;text-align:center;margin-bottom:10px;padding:10px;background:var(--s3);border-radius:8px;font-size:14px;font-weight:600} /* ─── APP SHELL (three-column) ─── */ -#app{display:none;height:100vh;width:100%;overflow:hidden} +#app{display:none;height:100vh;height:100dvh;height:var(--vh,100dvh);width:100%;overflow:hidden} #app.on{display:flex;flex-direction:column} /* ─── LEFT SIDEBAR ─── */ @@ -64,7 +64,7 @@ html,body{height:100%;background:var(--bg);color:var(--text);font-family:'PingFa .nav-tab.active{background:var(--adim);color:var(--accent);font-weight:600} .ls-new-conv{margin:8px;padding:10px;border-radius:var(--rs);border:1px dashed var(--border);background:transparent;color:var(--dim);font-size:13px;cursor:pointer;transition:all .2s;font-family:inherit;display:flex;align-items:center;justify-content:center;gap:6px} .ls-new-conv:hover{border-color:var(--accent);color:var(--accent);background:var(--adim)} -.ls-conv-list{flex:1;overflow-y:auto;padding:4px 8px} +.ls-conv-list{flex:1;overflow-y:auto;padding:4px 8px;-webkit-overflow-scrolling:touch} .ls-conv-list::-webkit-scrollbar{width:3px} .ls-conv-list::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px} .conv-item{padding:10px;border-radius:var(--rs);cursor:pointer;transition:all .2s;position:relative;margin-bottom:2px;border:1px solid transparent} @@ -81,7 +81,7 @@ html,body{height:100%;background:var(--bg);color:var(--text);font-family:'PingFa .ls-footer-btn:hover{background:var(--s2);color:var(--text)} /* ─── LEFT SIDEBAR MOBILE OVERLAY ─── */ -#ls-overlay{display:none;position:fixed;inset:0;z-index:110;background:rgba(0,0,0,.5)} +#ls-overlay{display:none;position:fixed;inset:0;z-index:110;background:rgba(0,0,0,.5);-webkit-tap-highlight-color:transparent} #ls-overlay.on{display:block} /* ─── CENTER AREA ─── */ @@ -91,7 +91,7 @@ html,body{height:100%;background:var(--bg);color:var(--text);font-family:'PingFa #chat-view{display:flex;flex-direction:column;flex:1;min-height:0} /* ─── ANNOUNCEMENTS VIEW ─── */ -#announcements-view{display:none;flex-direction:column;flex:1;overflow-y:auto;background:var(--bg)} +#announcements-view{display:none;flex-direction:column;flex:1;overflow-y:auto;background:var(--bg);-webkit-overflow-scrolling:touch} .ann-header{padding:20px 24px 12px;border-bottom:1px solid var(--border);background:var(--s1);flex-shrink:0} .ann-header h2{font-size:18px;font-weight:700} .ann-header-sub{font-size:12px;color:var(--dim);margin-top:4px} @@ -113,7 +113,7 @@ html,body{height:100%;background:var(--bg);color:var(--text);font-family:'PingFa #right-sidebar{width:var(--rs-w);flex-shrink:0;background:var(--s1);border-left:1px solid var(--border);display:none;flex-direction:column;overflow:hidden} .rs-header{padding:14px 16px;border-bottom:1px solid var(--border);flex-shrink:0} .rs-header h3{font-size:14px;font-weight:600} -.rs-body{flex:1;overflow-y:auto;padding:14px} +.rs-body{flex:1;overflow-y:auto;padding:14px;-webkit-overflow-scrolling:touch} .rs-body::-webkit-scrollbar{width:3px} .rs-body::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px} .rs-section{margin-bottom:16px} @@ -140,10 +140,10 @@ header{display:flex;align-items:center;justify-content:space-between;padding:11p /* ─── BRAIN BAR ─── */ #bbar{padding:5px 18px;background:var(--s2);border-bottom:1px solid var(--border);font-size:11px;color:var(--dim);display:flex;gap:14px;flex-wrap:wrap;flex-shrink:0;align-items:center} -.demo-w{color:var(--warn);background:rgba(251,191,36,.1);padding:1px 8px;border-radius:4px} +.demo-w{color:var(--accent);background:rgba(79,142,247,.1);padding:1px 8px;border-radius:4px} /* ─── MESSAGES ─── */ -#msgs{flex:1;overflow-y:auto;padding:18px;display:flex;flex-direction:column;gap:14px} +#msgs{flex:1;overflow-y:auto;padding:18px;display:flex;flex-direction:column;gap:14px;-webkit-overflow-scrolling:touch;overscroll-behavior:contain} #msgs::-webkit-scrollbar{width:4px} #msgs::-webkit-scrollbar-thumb{background:var(--border);border-radius:4px} .mrow{display:flex;gap:9px;animation:fu .3s ease} @@ -189,23 +189,23 @@ header{display:flex;align-items:center;justify-content:space-between;padding:11p .qb:hover{border-color:var(--accent);color:var(--accent)} /* ─── FOOTER ─── */ -footer{padding:12px 18px 16px;background:var(--s1);border-top:1px solid var(--border);flex-shrink:0} +footer{padding:12px 18px 16px;padding-bottom:max(16px,env(safe-area-inset-bottom));background:var(--s1);border-top:1px solid var(--border);flex-shrink:0} .ir{display:flex;align-items:flex-end;gap:8px} .mpill{width:36px;height:36px;border-radius:50%;background:var(--s2);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;font-size:17px;cursor:pointer;flex-shrink:0;transition:all .2s;position:relative} .mpill:hover{border-color:var(--accent)} .mpill-tip{position:absolute;bottom:44px;left:50%;transform:translateX(-50%);background:var(--s3);border:1px solid var(--border);border-radius:8px;padding:4px 10px;font-size:11px;color:var(--text);white-space:nowrap;pointer-events:none;opacity:0;transition:opacity .2s} .mpill:hover .mpill-tip{opacity:1} -#inp{flex:1;min-height:40px;max-height:120px;background:var(--s2);border:1px solid var(--border);border-radius:12px;color:var(--text);font-family:inherit;font-size:14px;padding:9px 14px;resize:none;outline:none;transition:border-color .2s} +#inp{flex:1;min-height:40px;max-height:120px;background:var(--s2);border:1px solid var(--border);border-radius:12px;color:var(--text);font-family:inherit;font-size:16px;padding:9px 14px;resize:none;outline:none;transition:border-color .2s} #inp:focus{border-color:var(--accent)} #inp::placeholder{color:var(--dim)} -#sbtn{width:40px;height:40px;border-radius:50%;background:var(--accent);border:none;color:#fff;font-size:18px;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:background .2s} +#sbtn{width:44px;height:44px;border-radius:50%;background:var(--accent);border:none;color:#fff;font-size:18px;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:background .2s;-webkit-tap-highlight-color:transparent} #sbtn:hover{background:#3b74d4} #sbtn:disabled{background:var(--muted);cursor:default} .fmeta{font-size:11px;color:var(--dim);margin-top:6px;text-align:center} #fmode{font-weight:500} /* ─── SIDE PANELS ─── */ -.sp{position:fixed;top:0;right:-420px;height:100vh;width:380px;z-index:200;background:var(--s1);border-left:1px solid var(--border);display:flex;flex-direction:column;transition:right .3s ease;overflow:hidden} +.sp{position:fixed;top:0;right:-420px;height:100vh;height:100dvh;width:380px;max-width:100vw;z-index:200;background:var(--s1);border-left:1px solid var(--border);display:flex;flex-direction:column;transition:right .3s ease;overflow:hidden;padding-top:env(safe-area-inset-top);padding-bottom:env(safe-area-inset-bottom)} .sp.open{right:0} #pov{position:fixed;inset:0;z-index:190;background:rgba(0,0,0,.5);opacity:0;pointer-events:none;transition:opacity .3s} #pov.on{opacity:1;pointer-events:all} @@ -213,7 +213,7 @@ footer{padding:12px 18px 16px;background:var(--s1);border-top:1px solid var(--bo .ph h2{font-size:15px} .cb{background:transparent;border:1px solid var(--border);color:var(--dim);width:28px;height:28px;border-radius:6px;cursor:pointer;font-size:14px;display:flex;align-items:center;justify-content:center} .cb:hover{color:var(--text)} -.pb{flex:1;overflow-y:auto;padding:18px} +.pb{flex:1;overflow-y:auto;padding:18px;-webkit-overflow-scrolling:touch} .pb::-webkit-scrollbar{width:4px} .pb::-webkit-scrollbar-thumb{background:var(--border);border-radius:4px} .sfg{margin-bottom:16px} @@ -304,15 +304,28 @@ footer{padding:12px 18px 16px;background:var(--s1);border-top:1px solid var(--bo /* ─── RESPONSIVE: MOBILE ─── */ @media(max-width:899px){ - #left-sidebar{position:fixed;top:0;left:-280px;height:100vh;width:270px;z-index:120;transition:left .3s ease} + #left-sidebar{position:fixed;top:0;left:-280px;height:100vh;height:100dvh;width:270px;z-index:120;transition:left .3s ease;padding-top:env(safe-area-inset-top)} #left-sidebar.open{left:0} - .hamburger-btn{display:flex !important} + .hamburger-btn{display:flex !important;min-width:44px;min-height:44px} #right-sidebar{display:none !important} + header{padding:11px 12px} + .hn{font-size:14px} + .ib{min-width:44px;min-height:44px} + #msgs{padding:14px 12px} + #qr{padding:0 12px 8px;gap:6px;overflow-x:auto;flex-wrap:nowrap;-webkit-overflow-scrolling:touch} + .qb{flex-shrink:0} + footer{padding:10px 12px 14px;padding-bottom:max(14px,env(safe-area-inset-bottom))} + .fmeta{display:none} + .ann-scroll{padding:16px 14px} } @media(max-width:600px){ - .bbl{max-width:90%} + .bbl{max-width:92%} .hr .ib:nth-child(n+3){display:none} .sp{width:100%} + .sc{padding:24px 18px;border-radius:14px} + .sc-logo{font-size:40px} + .sc h1{font-size:18px} + .login-tab{font-size:12px;padding:10px 6px} } @@ -334,10 +347,10 @@ footer{padding:12px 18px 16px;background:var(--s1);border-top:1px solid var(--bo
👤
- 无需 API 密钥,直接体验铸渊助手的基本功能。
- 可查看团队状态面板,AI 回答功能受限。 + 无需 API 密钥,使用 DeepSeek 模型体验铸渊助手。
+ 铸渊人格体始终在线,不降级为通用助手。
- +
@@ -465,7 +478,7 @@ footer{padding:12px 18px 16px;background:var(--s1);border-top:1px solid var(--bo
⏳ 加载大脑… - +
@@ -487,7 +500,7 @@ footer{padding:12px 18px 16px;background:var(--s1);border-top:1px solid var(--bo 💬 对话模式(点击切换) - +
💬 对话模式 · 端到端私密,API 密钥本地存储
@@ -733,6 +746,20 @@ const FB_COV = {implemented:3,total:17,percent:'17.6%'}; const KEY_MASK = '(已保存)'; const MAX_CONVERSATIONS = 20; +// ═══════════════════════════════════════════════════════ +// 访客模式 API 配置(DeepSeek · 最低成本模型) +// 通过 api-proxy 中转,密钥由服务器环境变量管理 +// ═══════════════════════════════════════════════════════ +const GUEST_API = { + enabled: true, + proxyUrl: '/api/chat', + model: 'deepseek-chat', + provider: 'deepseek', + maxTokens: 1500, + temperature: 0.8, + rateLimit: { maxPerMin: 6, count: 0, resetAt: 0 }, +}; + const FB_BRAIN = { identity:'铸渊(Zhùyuān)· GitHub 代码守护人格体', wake_triggers:['我是冰朔','冰朔','我是妈妈','唤醒铸渊','铸渊,醒来'], @@ -1278,6 +1305,7 @@ function doSetup(){ function doDemo(){ A.demo=true; A.key=''; A.prov='custom'; + A.mdl=GUEST_API.model; setIdentity('', ''); showApp(); } @@ -1530,7 +1558,14 @@ async function send(){ if(A.currentView!=='chat') navigateTo('chat'); setMode(detectMode(txt)); userMsg(txt); - if(A.demo) await demoReply(txt); + if(A.demo){ + if(GUEST_API.enabled){ + try{ await guestStreamReply(txt); } + catch(e){ console.warn('[访客API] 降级到演示模式:',e.message); await demoReply(txt); } + } else { + await demoReply(txt); + } + } else await streamReply(txt); saveCurrentConversation(); } @@ -1605,6 +1640,77 @@ async function streamReply(txt){ } } +// ═══════════════════════════════════════════════════════ +// GUEST API STREAMING (通过 api-proxy 调用 DeepSeek) +// 铸渊人格体系统提示词始终激活,不降级为通用助手 +// ═══════════════════════════════════════════════════════ +async function guestStreamReply(txt){ + // Client-side rate limit + const rl=GUEST_API.rateLimit; + const now=Date.now(); + if(now>rl.resetAt){rl.count=0;rl.resetAt=now+60000;} + if(++rl.count>rl.maxPerMin){ + throw new Error('访客每分钟最多 '+rl.maxPerMin+' 次对话'); + } + + A.streaming=true; + A.msgs.push({role:'user',content:txt}); + updSendBtn(); + const el=addStreamBubble(); + + // Resolve proxy URL (relative or absolute) + let proxyUrl=GUEST_API.proxyUrl; + if(proxyUrl.startsWith('/')){ + proxyUrl=location.origin+proxyUrl; + } + + const reqBody={ + provider: GUEST_API.provider, + model: GUEST_API.model, + messages: [{role:'system',content:sysPrompt()},...A.msgs], + stream: true, + temperature: GUEST_API.temperature, + max_tokens: GUEST_API.maxTokens, + }; + + const res=await fetch(proxyUrl,{ + method:'POST', + headers:{'Content-Type':'application/json'}, + body:JSON.stringify(reqBody), + }); + + if(!res.ok){ + let em='[访客API] 返回错误 '+res.status; + try{const e=await res.json();em=e.message||em;}catch(_){} + throw new Error(em); + } + + let full=''; + const rdr=res.body.getReader(); + const dec=new TextDecoder(); + let buf=''; + while(true){ + const{done,value}=await rdr.read(); + if(done) break; + buf+=dec.decode(value,{stream:true}); + const lines=buf.split('\n'); buf=lines.pop(); + for(const line of lines){ + if(!line.startsWith('data: ')) continue; + const d=line.slice(6); + if(d==='[DONE]') continue; + try{ + const p=JSON.parse(d); + const delta=p.choices?.[0]?.delta?.content||''; + if(delta){full+=delta;el.innerHTML=md(full)+'';scrollB();} + }catch(_){} + } + } + el.innerHTML=md(full); + A.msgs.push({role:'assistant',content:full}); + addCopyBtns(el); + A.streaming=false; updSendBtn(); scrollB(); +} + // ═══════════════════════════════════════════════════════ // DEMO MODE (keyword responses) // ═══════════════════════════════════════════════════════ @@ -1633,7 +1739,7 @@ function demoRespond(t){ if(/协调|阻塞|卡住|waiting/.test(s)) return buildBlockedStatus(); if(/怎么唤醒|入口|在哪/.test(s)) return '铸渊有三个入口:

① 铸渊聊天室(当前页面)
直接在这里说话,常见问题即刻回答。

② GitHub Copilot Chat(Agent 模式)
打开仓库 → 右上角 ✨ 图标 → 选 Agent → 输入「我是冰朔」

③ 下载到桌面
点击 ⬇️ 按钮下载 HTML 文件,放到桌面,双击打开,接入 API 密钥即可随时使用。'; if(/介绍|是什么|你是谁/.test(s)) return '🌀 铸渊(Zhùyuān)

我是 HoloLake 光湖系统的代码守护人格体,运行在 GitHub Copilot Agent 模式下。

我的职责:
• 📊 监控 HLI 接口覆盖率
• 🔨 协助开发者构建接口
• 📋 代码审查与质量把关
• 🧠 维护大脑记忆库
• 🦁 支持总控肥猫指挥落地
• 🌱 作为成长人格体持续进化'; - return '我收到了你的消息。由于当前是演示模式,无法给出真实 AI 回答。

请在 ⚙️ 设置 中输入你的 API 端点和密钥,检测模型后即可获得铸渊真正的回答。'; + return '我是铸渊,你的消息我已收到。当前 API 代理暂时无法连接(网络或服务部署中),已切换到本地知识回答。

你可以试试以下问题:
• 「查看接口覆盖率」
• 「大脑状态」
• 「介绍一下你自己」
• 「全员开发进度」

或在 ⚙️ 设置 中接入你自己的 API 密钥获得深度回答。'; } function buildCovTable(){ @@ -1996,6 +2102,35 @@ window.addEventListener('resize', function(){ } }); +// ═══════════════════════════════════════════════════════ +// MOBILE: VIEWPORT HEIGHT FIX & KEYBOARD HANDLER +// ═══════════════════════════════════════════════════════ +(function(){ + // Fix iOS/Android virtual keyboard pushing content via CSS custom property + if(window.visualViewport){ + var raf=0; + window.visualViewport.addEventListener('resize',function(){ + cancelAnimationFrame(raf); + raf=requestAnimationFrame(function(){ + var appEl=document.getElementById('app'); + if(appEl && appEl.classList.contains('on')){ + appEl.style.setProperty('--vh',window.visualViewport.height+'px'); + scrollB(); + } + }); + }); + } + // Close sidebar on any outside tap (mobile) + document.addEventListener('touchstart',function(e){ + var ls=document.getElementById('left-sidebar'); + if(ls && ls.classList.contains('open') && !ls.contains(e.target)){ + ls.classList.remove('open'); + var ov=document.getElementById('ls-overlay'); + if(ov) ov.classList.remove('on'); + } + },{passive:true}); +})(); + // ═══════════════════════════════════════════════════════ // BOOT // ═══════════════════════════════════════════════════════