From d3a2a09daa4b1157a88032ec61d7092668dbbd2d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Apr 2026 09:19:37 +0000 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20Restructure=20home=20page=20as=20?= =?UTF-8?q?=E5=85=89=E6=B9=96=E8=AF=AD=E8=A8=80=E4=B8=96=E7=95=8C=E5=85=A5?= =?UTF-8?q?=E5=8F=A3=E5=A4=A7=E5=8E=85=20with=20GPT-style=20chat=20layout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace hero landing with full-screen GPT-style chat interface - Add left sidebar with chat history, search, and navigation - Make chat window full-height (no more floating panel) - Add user ID (编号) verification modal - Add persona process visualization (brain activity indicators) - Remove team member displays, replaced with dev status note - Responsive design for PC (sidebar always visible) and mobile (hamburger menu) - Keep backend API integration intact - Keep all existing pages (editor, desk, etc.) accessible via sidebar nav - Conversation history saved to localStorage with CRUD operations Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/6138ad64-32ec-4191-9730-de0bf24e87a8 Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- docs/index.html | 920 +++++++++++++++++++++++++++--------------------- 1 file changed, 521 insertions(+), 399 deletions(-) diff --git a/docs/index.html b/docs/index.html index 7af7e013..bca6fc7c 100644 --- a/docs/index.html +++ b/docs/index.html @@ -332,7 +332,7 @@ label{display:block;font-size:12px;color:var(--dim);margin-bottom:4px;font-weigh /* ═══ Viewport-Fit Layout (Desktop ≥961px) ═══ */ @media(min-width:961px){ - #pg-home{overflow-y:auto;display:flex;flex-direction:column} + #pg-home{overflow:hidden;display:flex;flex-direction:column;height:100vh;height:100dvh} } /* ═══ Touch-Driven Sizing (Device Agent 适配) ═══ */ @@ -720,6 +720,142 @@ label{display:block;font-size:12px;color:var(--dim);margin-bottom:4px;font-weigh .app-card-arrow{font-size:18px;color:var(--accent);opacity:.5;flex-shrink:0;transition:all .3s} .app-card:hover .app-card-arrow{opacity:1;transform:translateX(4px)} +/* ═══ 光湖语言世界 · GPT-Style Chat Layout ═══ */ +.hl-app{display:flex;height:100vh;height:100dvh;width:100%;overflow:hidden;position:relative} + +/* ── Sidebar ── */ +.hl-sidebar{width:280px;flex-shrink:0;display:flex;flex-direction:column;background:rgba(8,12,28,.95);border-right:1px solid rgba(100,100,200,.12);z-index:20;transition:transform .3s cubic-bezier(.4,0,.2,1)} +.hl-sidebar-header{display:flex;align-items:center;justify-content:space-between;padding:16px 16px 12px;border-bottom:1px solid rgba(100,100,200,.1)} +.hl-logo{display:flex;align-items:center;gap:10px} +.hl-logo-icon{font-size:24px;filter:drop-shadow(0 0 10px rgba(138,180,248,.4))} +.hl-logo-text{font-size:15px;font-weight:700;background:linear-gradient(135deg,#e0e0f0,#8ab4f8,#a78bfa);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text} +.hl-new-chat-btn{width:36px;height:36px;border-radius:10px;border:1px solid rgba(100,100,200,.2);background:transparent;color:var(--dim);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .3s} +.hl-new-chat-btn:hover{border-color:var(--accent);color:var(--accent);background:rgba(138,180,248,.08)} +.hl-sidebar-search{padding:10px 14px} +.hl-search-input{width:100%;padding:8px 12px;background:rgba(20,24,48,.6);border:1px solid rgba(100,100,200,.12);border-radius:10px;color:var(--text);font-size:13px;outline:none;font-family:var(--f);transition:border-color .3s} +.hl-search-input:focus{border-color:rgba(138,180,248,.4)} +.hl-sidebar-chats{flex:1;overflow-y:auto;padding:4px 8px} +.hl-chat-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:10px;cursor:pointer;transition:all .25s;margin-bottom:2px;border:1px solid transparent} +.hl-chat-item:hover{background:rgba(138,180,248,.06);border-color:rgba(100,100,200,.12)} +.hl-chat-item.active{background:rgba(138,180,248,.1);border-color:rgba(138,180,248,.2)} +.hl-chat-item-icon{font-size:16px;flex-shrink:0;opacity:.6} +.hl-chat-item-text{flex:1;min-width:0} +.hl-chat-item-title{font-size:13px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} +.hl-chat-item-time{font-size:10px;color:var(--dim);margin-top:2px} +.hl-chat-item-del{opacity:0;font-size:12px;color:var(--dim);cursor:pointer;padding:4px;border-radius:4px;transition:all .2s;flex-shrink:0} +.hl-chat-item:hover .hl-chat-item-del{opacity:.6} +.hl-chat-item-del:hover{opacity:1;color:var(--err);background:rgba(248,113,113,.1)} +.hl-sidebar-nav{padding:8px;border-top:1px solid rgba(100,100,200,.1);display:flex;flex-direction:column;gap:2px} +.hl-nav-item{display:flex;align-items:center;gap:10px;padding:10px 14px;border-radius:10px;cursor:pointer;font-size:13px;color:var(--dim);transition:all .25s;border:none;background:none;width:100%;text-align:left;font-family:var(--f)} +.hl-nav-item:hover{background:rgba(138,180,248,.06);color:var(--text)} +.hl-sidebar-footer{padding:12px 14px;border-top:1px solid rgba(100,100,200,.1)} +.hl-sidebar-status{display:flex;align-items:center;gap:8px;font-size:11px;color:var(--dim);margin-bottom:8px} +.hl-status-text{font-family:var(--m)} +.hl-sidebar-user{display:flex;align-items:center;gap:8px;padding:8px 10px;background:rgba(20,24,48,.5);border-radius:10px;cursor:pointer;transition:background .3s} +.hl-sidebar-user:hover{background:rgba(138,180,248,.08)} +.hl-user-icon{font-size:18px} +.hl-user-name{font-size:12px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} + +/* Sidebar toggle (mobile) */ +.hl-sidebar-toggle{display:none;position:fixed;top:12px;left:12px;z-index:25;width:42px;height:42px;border-radius:12px;border:1px solid rgba(100,100,200,.2);background:rgba(8,12,28,.9);color:var(--text);font-size:18px;cursor:pointer;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);transition:all .3s} +.hl-sidebar-toggle:hover{border-color:var(--accent)} +.hl-sidebar-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:18;opacity:0;transition:opacity .3s} +.hl-sidebar-overlay.open{opacity:1} + +@media(max-width:768px){ + .hl-sidebar{position:fixed;left:0;top:0;bottom:0;transform:translateX(-100%);z-index:22;width:min(300px,85vw)} + .hl-sidebar.open{transform:translateX(0)} + .hl-sidebar-toggle{display:flex;align-items:center;justify-content:center} + .hl-sidebar-overlay{display:block;pointer-events:none} + .hl-sidebar-overlay.open{pointer-events:auto} +} + +/* ── Main Chat Area ── */ +.hl-main{flex:1;display:flex;flex-direction:column;min-width:0;position:relative} +.hl-chat-header{display:flex;align-items:center;justify-content:space-between;padding:12px 20px;border-bottom:1px solid rgba(100,100,200,.1);background:rgba(8,12,28,.6);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);flex-shrink:0} +.hl-chat-persona{display:flex;align-items:center;gap:12px} +.hl-persona-avatar{width:42px;height:42px;border-radius:50%;background:linear-gradient(135deg,#34d399,#4ade80);display:flex;align-items:center;justify-content:center;font-size:20px;flex-shrink:0;box-shadow:0 0 20px rgba(52,211,153,.2)} +.hl-persona-name{font-size:15px;font-weight:700} +.hl-persona-sub{font-size:11px;color:var(--dim);margin-top:2px} +.hl-chat-status{font-size:11px;padding:4px 12px;background:rgba(52,211,153,.1);border:1px solid rgba(52,211,153,.2);border-radius:20px;color:var(--ok);font-family:var(--m);font-weight:600;flex-shrink:0} +@media(max-width:768px){ + .hl-chat-header{padding:12px 16px 12px 60px} + .hl-persona-sub{display:none} +} + +/* ── Chat Messages ── */ +.hl-chat-messages{flex:1;overflow-y:auto;padding:20px;display:flex;flex-direction:column;gap:16px;-webkit-overflow-scrolling:touch;scroll-behavior:smooth} +@media(max-width:768px){.hl-chat-messages{padding:16px 12px}} + +/* Welcome screen */ +.hl-welcome{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:60vh;text-align:center;animation:heroFadeUp .8s ease-out both;padding:20px} +.hl-welcome-icon{font-size:72px;margin-bottom:20px;filter:drop-shadow(0 0 30px rgba(138,180,248,.4));animation:uptimePulse 6s ease-in-out infinite} +.hl-welcome-title{font-size:clamp(28px,5vw,42px);font-weight:800;background:linear-gradient(135deg,#e0e0f0 0%,#8ab4f8 40%,#a78bfa 80%,#c4b5fd 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;margin-bottom:8px} +.hl-welcome-sub{font-size:clamp(13px,2.5vw,16px);color:var(--dim);margin-bottom:36px;letter-spacing:1px} +.hl-welcome-cards{display:grid;grid-template-columns:1fr 1fr;gap:12px;max-width:460px;width:100%;margin-bottom:32px} +@media(max-width:480px){.hl-welcome-cards{grid-template-columns:1fr;max-width:280px}} +.hl-wc{padding:16px 14px;background:rgba(18,18,42,.55);border:1px solid rgba(100,100,200,.22);border-radius:14px;cursor:pointer;transition:all .35s;text-align:left;display:flex;align-items:flex-start;gap:12px} +.hl-wc:hover{border-color:rgba(138,180,248,.4);box-shadow:0 0 24px rgba(138,180,248,.1);transform:translateY(-2px)} +.hl-wc:active{transform:scale(.98)} +.hl-wc-icon{font-size:22px;flex-shrink:0;margin-top:2px} +.hl-wc-text{font-size:13px;font-weight:600;line-height:1.5} +.hl-wc-text small{font-weight:400;color:var(--dim);font-size:11px} +.hl-welcome-dev{padding:12px 20px;background:rgba(18,18,42,.4);border:1px solid rgba(100,100,200,.15);border-radius:12px;font-size:12px;color:var(--dim)} +.hl-welcome-dev .tag{margin-left:6px} + +/* Message bubbles (reuse cm classes) */ +.cm{max-width:min(85%,720px);padding:14px 18px;border-radius:16px;font-size:15px;line-height:1.8;word-break:break-word;animation:msgIn .3s ease-out} +@keyframes msgIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}} +.cm.u{align-self:flex-end;background:var(--accent);color:#fff;border-bottom-right-radius:4px} +.cm.b{align-self:flex-start;background:rgba(18,22,44,.75);border:1px solid rgba(100,100,200,.18);border-bottom-left-radius:4px} +.cm.s{align-self:center;background:none;color:var(--muted);font-size:12px;padding:4px} +.cm-m{display:flex;gap:5px;margin-top:8px;font-size:11px;color:var(--muted);opacity:.7} + +/* Process visualization */ +.hl-process{padding:8px 20px;border-top:1px solid rgba(100,100,200,.1);flex-shrink:0;background:rgba(8,12,28,.5)} +.hl-process-inner{display:flex;align-items:center;gap:12px;padding:8px 14px;background:rgba(138,180,248,.04);border:1px solid rgba(138,180,248,.1);border-radius:12px} +.hl-process-spinner{width:16px;height:16px;border:2px solid rgba(138,180,248,.2);border-top-color:var(--accent);border-radius:50%;animation:spin .8s linear infinite;flex-shrink:0} +@keyframes spin{to{transform:rotate(360deg)}} +.hl-process-steps{font-size:12px;color:var(--accent);font-family:var(--m)} + +/* ── Chat Input ── */ +.hl-chat-input-wrap{padding:12px 20px 16px;flex-shrink:0;background:rgba(8,12,28,.4);border-top:1px solid rgba(100,100,200,.08)} +@media(max-width:768px){.hl-chat-input-wrap{padding:10px 12px 14px;padding-bottom:calc(14px + var(--sb))}} +.hl-chat-input-box{display:flex;align-items:flex-end;gap:10px;max-width:800px;margin:0 auto;background:rgba(18,22,44,.6);border:1px solid rgba(100,100,200,.2);border-radius:16px;padding:8px 14px;transition:border-color .3s,box-shadow .3s} +.hl-chat-input-box:focus-within{border-color:rgba(138,180,248,.4);box-shadow:0 0 20px rgba(138,180,248,.08)} +.hl-chat-input{flex:1;background:none;border:none;color:var(--text);font-size:15px;font-family:var(--f);outline:none;resize:none;max-height:150px;min-height:24px;line-height:1.6;padding:4px 0;-webkit-appearance:none} +.hl-chat-input::placeholder{color:var(--muted)} +.hl-send-btn{width:38px;height:38px;border-radius:50%;background:var(--accent);border:none;color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:all .2s} +.hl-send-btn:hover{background:var(--accent2);transform:scale(1.05)} +.hl-send-btn:disabled{opacity:.3;cursor:default;transform:none} +.hl-send-btn:active{transform:scale(.93)} +.hl-input-footer{display:flex;justify-content:space-between;align-items:center;max-width:800px;margin:6px auto 0;padding:0 4px} +.hl-input-hint{font-size:11px;color:var(--muted)} +.hl-input-model{font-size:11px;color:var(--dim);font-family:var(--m)} +@media(max-width:480px){.hl-input-hint{display:none}} + +/* ── User ID Modal ── */ +.hl-modal-overlay{position:fixed;inset:0;z-index:100;background:rgba(0,0,0,.6);display:flex;align-items:center;justify-content:center;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);animation:fadeIn .3s ease-out} +@keyframes fadeIn{from{opacity:0}to{opacity:1}} +.hl-modal{background:rgba(14,18,38,.95);border:1px solid rgba(100,100,200,.2);border-radius:20px;padding:40px 32px;max-width:420px;width:90%;text-align:center;box-shadow:0 24px 80px rgba(0,0,0,.5),0 0 60px rgba(138,180,248,.08);animation:modalIn .4s ease-out} +@keyframes modalIn{from{opacity:0;transform:scale(.92) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}} +.hl-modal-icon{font-size:56px;margin-bottom:16px;filter:drop-shadow(0 0 20px rgba(52,211,153,.3))} +.hl-modal-title{font-size:22px;font-weight:700;margin-bottom:8px} +.hl-modal-desc{font-size:13px;color:var(--dim);margin-bottom:24px;line-height:1.6} +.hl-modal-form{display:flex;flex-direction:column;gap:0} +.hl-modal-input{padding:12px 16px;background:rgba(20,24,48,.6);border:1px solid rgba(100,100,200,.18);border-radius:12px;color:var(--text);font-size:15px;outline:none;font-family:var(--f);transition:border-color .3s} +.hl-modal-input:focus{border-color:rgba(138,180,248,.4)} +.hl-modal-btn{margin-top:16px;padding:14px;background:linear-gradient(135deg,var(--accent),var(--accent2));border:none;border-radius:12px;color:#fff;font-size:16px;font-weight:700;cursor:pointer;font-family:var(--f);transition:all .3s} +.hl-modal-btn:hover{opacity:.9;box-shadow:0 4px 20px rgba(138,180,248,.3)} +.hl-modal-skip{font-size:12px;color:var(--dim);margin-top:16px;cursor:pointer;transition:color .2s} +.hl-modal-skip:hover{color:var(--accent)} + +/* ── Typing indicator ── */ +.ct{font-size:13px;color:var(--dim);padding:8px 18px} +.ct span{animation:bk 1.4s infinite;font-size:15px} +.ct span:nth-child(2){animation-delay:.2s} +.ct span:nth-child(3){animation-delay:.4s} + /* ═══ PAGE: Bandwidth Sharing (带宽共享) ═══ */ @@ -729,51 +865,120 @@ label{display:block;font-size:12px;color:var(--dim);margin-bottom:4px;font-weigh
- +
-
-
🌀 零感域 · 零点原核
-
在线
-
-
-

零感域 · 零点原核

-

AGE OS · 语言驱动操作系统

-

「语言 = 现实」

- -
-
-
-
-
码字工作台
-
网文创作 · 人格体陪伴
沉浸式写作环境
-
- 在线 - 知秋陪伴 + +
+ + + + + +
+ + +
+ +
+
+
🏛️
+
+
铸渊 · 光湖语言世界守护者
+
AGE OS · 语言驱动操作系统 · 代码仓库执行人格体
+
+
+
ready
+
+ + +
+ +
+
🌊
+

光湖语言世界

+

人格体一半 · 人类一半 · 语言 = 现实

+
+
+ 👋 + 自我介绍
告诉铸渊你是谁
+
+
+ 🧭 + 使用指南
查看完整指令
+
+
+ ✍️ + 码字工作台
进入网文创作
+
+
+ 📊 + 系统状态
查看运行数据
+
+
+
+

🔖 网文行业大模型 · 由光湖人类主控团队开发维护 · 开发中

+
-
-
-
- 语言膜完整 · 没有缺口的圆 - v50.0 -
+ + - + +
+
+ + +
+ +
+
@@ -865,28 +1070,12 @@ label{display:block;font-size:12px;color:var(--dim);margin-bottom:4px;font-weigh
- +
-
✍️ 网文行业人类主控团队
+
✍️ 网文行业大模型
-
🐱
-
肥猫 + 舒舒
男频主控 · PER-SS001
-
-
-
🍊
-
桔子 + 晨星
女频主控 · PER-CX001
-
-
-
📄
-
页页 + 坍缩核
女频副主控 · PER-XTS001
-
-
-
🌸
-
花儿 + 糖星云
女频副主控 · PER-TXY001
-
-
-
🌊
-
Awen + 知秋
光湖技术主控 · PER-ZQ001
+
🤖
+
网文行业大模型
由光湖人类主控团队开发维护 · 当前进度:开发中
@@ -1398,46 +1587,18 @@ label{display:block;font-size:12px;color:var(--dim);margin-bottom:4px;font-weigh
- - - - -
- - -
-
-
🏛️
-
铸渊
光湖灯塔 · 守护者
-
ready
-
-
-
—— 与铸渊对话 ——
-
你好!我是铸渊 🌀

告诉我你是谁,我会记住你。
说「我要码字」进入码字工作台。
说「模块」选择创作方向。
说「灵感」记录好点子。
说「帮助」查看完整指令。
铸渊·v50.0
-
-
- - -
- -
-
🔑 接入大模型 API(支持所有三方)
-
-
- -
-
- - -
-
未连接 · 粘贴密钥后自动检测可用模型
- + + @@ -1716,10 +1877,8 @@ function go(target){ currentPage=target; - // Editor mode: shrink chat fab to not disturb writing - var fab=document.getElementById('chatFab'); - if(target==='editor'){fab.classList.add('editor-mode')} - else{fab.classList.remove('editor-mode');stopEditorTimer()} + // Editor mode + if(target!=='editor'){stopEditorTimer()} // Trigger page-specific renders if(target==='desk')renderWorkList(); @@ -2208,19 +2367,133 @@ function recovReply(){ } /* ════════════════════════════════════════ - CHAT (语言驱动核心) + CHAT (语言驱动核心 · GPT-style全屏版) ════════════════════════════════════════ */ -var chatOpen=false,sending=false; -var chatFab=document.getElementById('chatFab'); -var chatP=document.getElementById('chatP'); +var sending=false; var chatIn=document.getElementById('chatIn'); var chatMs=document.getElementById('chatMs'); -var chatOverlay=document.getElementById('chatOverlay'); var mCalls=0; -chatFab.onclick=null; // Overridden by draggable FAB code below +// Conversation management +var HL_CONV_KEY='hl-conversations'; +var HL_ACTIVE_CONV='hl-active-conv'; +var conversations=[]; +var activeConvId=null; + +function loadConversations(){ + try{var d=localStorage.getItem(HL_CONV_KEY);conversations=d?JSON.parse(d):[]}catch(e){conversations=[]} + try{activeConvId=localStorage.getItem(HL_ACTIVE_CONV)||null}catch(e){} +} +function saveConversations(){ + try{localStorage.setItem(HL_CONV_KEY,JSON.stringify(conversations))}catch(e){} + if(activeConvId)try{localStorage.setItem(HL_ACTIVE_CONV,activeConvId)}catch(e){} +} +function newConversation(){ + var id='conv-'+Date.now()+'-'+Math.random().toString(36).substr(2,4); + var conv={id:id,title:'新对话',messages:[],created:new Date().toISOString(),updated:new Date().toISOString()}; + conversations.unshift(conv); + activeConvId=id; + saveConversations(); + renderChatHistory(); + clearChatUI(); + return conv; +} +function getActiveConv(){return conversations.find(function(c){return c.id===activeConvId})||null} +function switchConversation(id){ + activeConvId=id; + try{localStorage.setItem(HL_ACTIVE_CONV,id)}catch(e){} + renderChatHistory(); + renderConversationMessages(); +} +function deleteConversation(id){ + conversations=conversations.filter(function(c){return c.id!==id}); + if(activeConvId===id){ + activeConvId=conversations.length>0?conversations[0].id:null; + } + saveConversations(); + renderChatHistory(); + if(activeConvId)renderConversationMessages(); + else clearChatUI(); +} +function clearChatUI(){ + chatMs.innerHTML=''; + var welcome=document.getElementById('hlWelcome'); + if(!welcome){ + // Recreate welcome + var w=document.createElement('div'); + w.className='hl-welcome';w.id='hlWelcome'; + w.innerHTML='
🌊

光湖语言世界

人格体一半 · 人类一半 · 语言 = 现实

🔖 网文行业大模型 · 由光湖人类主控团队开发维护 · 开发中

'; + chatMs.appendChild(w); + } +} +function renderConversationMessages(){ + var conv=getActiveConv(); + chatMs.innerHTML=''; + if(!conv||conv.messages.length===0){ + clearChatUI();return; + } + conv.messages.forEach(function(m){ + var d=document.createElement('div'); + d.className='cm '+m.type; + var h=esc(m.text).replace(/\n/g,'
'); + if(m.type==='b'&&m.meta){h+='
'+esc(m.meta.m||'铸渊')+'·'+esc(m.meta.t||'')+'
'} + d.innerHTML=h; + chatMs.appendChild(d); + }); + chatMs.scrollTop=chatMs.scrollHeight; +} +function renderChatHistory(){ + var el=document.getElementById('hlChatList'); + if(!el)return; + var searchVal=(document.getElementById('hlSearchChats')||{}).value||''; + var filtered=conversations; + if(searchVal.trim()){ + var q=searchVal.trim().toLowerCase(); + filtered=conversations.filter(function(c){return c.title.toLowerCase().indexOf(q)!==-1}); + } + if(filtered.length===0){ + el.innerHTML='
暂无对话记录
开始你的第一次对话吧
'; + return; + } + el.innerHTML=filtered.map(function(c){ + var isActive=c.id===activeConvId; + var timeStr=''; + try{var d=new Date(c.updated);timeStr=d.toLocaleDateString('zh-CN',{month:'short',day:'numeric'})}catch(e){} + return '
'+ + '💬'+ + '
'+esc(c.title)+'
'+timeStr+'
'+ + '
'; + }).join(''); + el.querySelectorAll('.hl-chat-item').forEach(function(item){ + item.onclick=function(e){ + if(e.target.hasAttribute('data-del')){ + e.stopPropagation(); + var did=e.target.getAttribute('data-del'); + deleteConversation(did); + return; + } + var cid=this.getAttribute('data-cid'); + switchConversation(cid); + }; + }); +} + +// Init conversations +loadConversations(); +renderChatHistory(); +if(activeConvId){renderConversationMessages()} + +// New chat button +document.getElementById('hlNewChat').onclick=function(){newConversation()}; +// Search +var hlSearchInput=document.getElementById('hlSearchChats'); +if(hlSearchInput){hlSearchInput.oninput=function(){renderChatHistory()}} function chatMsg(text,type,meta){ + // Hide welcome on first message + var welcome=document.getElementById('hlWelcome'); + if(welcome)welcome.remove(); + var d=document.createElement('div'); d.className='cm '+type; var h=esc(text).replace(/\n/g,'
'); @@ -2228,10 +2501,51 @@ function chatMsg(text,type,meta){ d.innerHTML=h; chatMs.appendChild(d); chatMs.scrollTop=chatMs.scrollHeight; + + // Save to conversation + var conv=getActiveConv(); + if(!conv){conv=newConversation()} + conv.messages.push({text:text,type:type,meta:meta||null,time:new Date().toISOString()}); + // Update title from first user message + if(type==='u'&&conv.title==='新对话'){ + conv.title=text.substring(0,30)+(text.length>30?'...':''); + } + conv.updated=new Date().toISOString(); + saveConversations(); + renderChatHistory(); } -function showTyp(){var d=document.createElement('div');d.className='ct';d.id='ctyp';d.innerHTML='铸渊思考中 ···';chatMs.appendChild(d);chatMs.scrollTop=chatMs.scrollHeight} -function hideTyp(){var e=document.getElementById('ctyp');if(e)e.remove()} +// Process visualization +function showProcess(steps){ + var el=document.getElementById('hlProcess'); + var stepsEl=document.getElementById('hlProcessSteps'); + if(el&&stepsEl){ + stepsEl.textContent=steps; + el.style.display=''; + } +} +function hideProcess(){ + var el=document.getElementById('hlProcess'); + if(el)el.style.display='none'; +} + +function showTyp(){ + showProcess('铸渊思考中...'); + var d=document.createElement('div');d.className='ct';d.id='ctyp';d.innerHTML='铸渊思考中 ···';chatMs.appendChild(d);chatMs.scrollTop=chatMs.scrollHeight; +} +function hideTyp(){ + hideProcess(); + var e=document.getElementById('ctyp');if(e)e.remove(); +} + +// Textarea auto-resize +chatIn.addEventListener('input',function(){ + this.style.height='24px'; + this.style.height=Math.min(this.scrollHeight,150)+'px'; +}); +chatIn.addEventListener('keydown',function(e){ + if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();send()} +}); // ─── 语言指令路由 ─── function routeCommand(msg){ @@ -2302,11 +2616,13 @@ async function send(){ // 3. 调用API —— 优先用用户自己的API Key(直接走用户网络),其次尝试后端 sending=true;document.getElementById('chatSnd').disabled=true;showTyp(); + showProcess('🧠 铸渊正在连接语言核...'); var replied=false; var backendError=''; // 用户配了API Key → 直接用用户的网络通道调用,不经过后端 if(apiCfg.connected&&apiCfg.key){ + showProcess('🔗 通过用户API通道连接 '+apiCfg.model+'...'); try{ var endpoint=apiCfg.baseUrl?apiCfg.baseUrl.replace(/\/+$/,'')+'/chat/completions':'https://api.openai.com/v1/chat/completions'; var apiRes=await fetch(endpoint,{ @@ -2324,7 +2640,7 @@ async function send(){ if(apiData.choices&&apiData.choices[0]&&apiData.choices[0].message){ chatMsg(apiData.choices[0].message.content,'b',{m:apiCfg.model,t:'用户API'}); mCalls++;document.getElementById('mC').textContent=mCalls; - document.getElementById('chatTg').textContent=apiCfg.model; + var mi=document.getElementById('hlModelInfo');if(mi)mi.textContent='🔑 '+apiCfg.model; document.getElementById('mM').textContent=apiCfg.model; replied=true; } @@ -2333,6 +2649,7 @@ async function send(){ // 用户没配Key或调用失败 → 尝试后端(含自动重试) if(!replied){ + showProcess('🌊 通过铸渊后端服务连接...'); var retryCount=0;var maxRetries=2; while(retryCount<=maxRetries&&!replied){ try{ @@ -2347,7 +2664,7 @@ async function send(){ chatMsg(data.message,'b',{m:data.model||'铸渊',t:data.tier||''}); if(data.tier!=='free')mCalls++; document.getElementById('mC').textContent=mCalls; - document.getElementById('chatTg').textContent=data.model||'ready'; + var mi2=document.getElementById('hlModelInfo');if(mi2)mi2.textContent=data.model||'ready'; if(data.model)document.getElementById('mM').textContent=data.model; }else if(data.error){ backendError=data.message||'服务端错误'; @@ -2368,8 +2685,7 @@ async function send(){ var offlineMsg=offline(msg); if(backendError){offlineMsg+='\n\n⚠️ 后端状态: '+backendError+'\n点击右下角💬重试,或配置API密钥直连大模型。'} chatMsg(offlineMsg,'b',{m:'铸渊',t:'本地智能'}); - document.getElementById('chatTg').textContent='离线'; - document.getElementById('chatTg').style.color='var(--err,#f87171)'; + var mi3=document.getElementById('hlModelInfo');if(mi3)mi3.textContent='离线模式'; } sending=false;document.getElementById('chatSnd').disabled=false; @@ -2438,164 +2754,17 @@ function offline(msg){ } document.getElementById('chatSnd').onclick=send; -chatIn.onkeydown=function(e){if(e.key==='Enter'){e.preventDefault();send()}}; /* ════════════════════════════════════════ - API KEY MANAGEMENT (自由格式 · 自动检测模型) + API KEY MANAGEMENT (from localStorage · UI moved to future settings) ════════════════════════════════════════ */ var apiCfg={key:null,model:'',baseUrl:'',connected:false,models:[]}; -var COMMON_ENDPOINTS=[ - 'https://api.openai.com/v1', - 'https://api.openai-proxy.com/v1', - 'https://api.chatanywhere.tech/v1' -]; try{var ak=localStorage.getItem('hl-api');if(ak){var ap=JSON.parse(ak);if(ap.key){apiCfg=ap;apiCfg.connected=true}}}catch(e){} - -// Restore UI state -(function(){ - var tog=document.getElementById('chatApiTog'); - var bd=document.getElementById('chatApiBd'); - var st=document.getElementById('apiSt'); - var keyInp=document.getElementById('apiKeyInp'); - var modelSel=document.getElementById('apiModelSel'); - var baseUrlInp=document.getElementById('apiBaseUrl'); - var modelListDiv=document.getElementById('apiModelList'); - if(!tog||!bd)return; - - if(apiCfg.connected){ - st.textContent='✅ 已连接 · '+apiCfg.model; - st.style.color='var(--ok)'; - if(apiCfg.baseUrl)baseUrlInp.value=apiCfg.baseUrl; - // Restore models list - if(apiCfg.models&&apiCfg.models.length>0){ - modelSel.innerHTML=apiCfg.models.map(function(m){return''}).join(''); - modelListDiv.style.display='block'; - } - } - - tog.onclick=function(){ - var isOpen=bd.classList.toggle('open'); - tog.classList.toggle('open',isOpen); - }; - - // Model selection change - modelSel.onchange=function(){ - if(!apiCfg.connected)return; - apiCfg.model=this.value; - try{localStorage.setItem('hl-api',JSON.stringify(apiCfg))}catch(e){} - st.textContent='✅ 已切换模型 · '+apiCfg.model; - document.getElementById('chatTg').textContent=apiCfg.model; - }; - - // Auto-detect: try to fetch /v1/models - async function detectModels(baseUrl,key){ - var url=baseUrl.replace(/\/+$/,'')+'/models'; - try{ - var r=await fetch(url,{ - headers:{'Authorization':'Bearer '+key}, - signal:AbortSignal.timeout(10000) - }); - if(!r.ok)return[]; - var data=await r.json(); - if(data.data&&Array.isArray(data.data)){ - return data.data.map(function(m){return m.id}).filter(function(id){ - // Filter to chat-capable models - return /gpt|claude|gemini|glm|qwen|deepseek|yi-|llama|mistral|chat|turbo/i.test(id); - }).sort(); - } - }catch(e){} - return[]; - } - - // Test connection with a simple request - async function testConnection(baseUrl,key,model){ - var url=baseUrl.replace(/\/+$/,'')+'/chat/completions'; - try{ - var r=await fetch(url,{ - method:'POST', - headers:{'Content-Type':'application/json','Authorization':'Bearer '+key}, - body:JSON.stringify({model:model,messages:[{role:'user',content:'hi'}],max_tokens:5}), - signal:AbortSignal.timeout(15000) - }); - return r.ok; - }catch(e){return false} - } - - document.getElementById('apiConnBtn').onclick=async function(){ - var key=keyInp.value.trim(); - if(!key){keyInp.focus();return;} - var userBase=baseUrlInp.value.trim(); - var btn=this; - btn.disabled=true;btn.textContent='检测中…'; - st.textContent='🔍 正在检测可用模型…';st.style.color='var(--dim)'; - - var foundModels=[]; - var workingBase=''; - - // If user provided a base URL, try that first - if(userBase){ - st.textContent='🔍 检测 '+userBase+' …'; - foundModels=await detectModels(userBase,key); - if(foundModels.length>0)workingBase=userBase; - } - - // If no models found, try common endpoints - if(foundModels.length===0){ - for(var i=0;i0){workingBase=COMMON_ENDPOINTS[i];break;} - } - } - - if(foundModels.length>0){ - // Show model list - modelSel.innerHTML=foundModels.map(function(m){return''}).join(''); - modelListDiv.style.display='block'; - - // Auto-select a reasonable default - var defaultModel=foundModels.find(function(m){return/gpt-4o-mini/i.test(m)})|| - foundModels.find(function(m){return/gpt-4o/i.test(m)})|| - foundModels.find(function(m){return/gpt-4/i.test(m)})|| - foundModels.find(function(m){return/claude/i.test(m)})|| - foundModels[0]; - modelSel.value=defaultModel; - - apiCfg={key:key,model:defaultModel,baseUrl:workingBase,connected:true,models:foundModels}; - try{localStorage.setItem('hl-api',JSON.stringify(apiCfg))}catch(e){} - st.textContent='✅ 检测到 '+foundModels.length+' 个模型 · 当前:'+defaultModel; - st.style.color='var(--ok)'; - document.getElementById('chatTg').textContent=defaultModel; - chatMsg('🔑 API已连接 · 检测到'+foundModels.length+'个可用模型\n当前使用:'+defaultModel+'\n可在下拉菜单切换模型','b',{m:'铸渊',t:'自定义'}); - }else{ - // Can't get model list, try direct connection test with common models - st.textContent='🔍 模型列表不可用,尝试直连测试…'; - var tryBase=userBase||COMMON_ENDPOINTS[0]; - var testModels=['gpt-4o-mini','gpt-4o','gpt-3.5-turbo','deepseek-chat','claude-3-haiku-20240307']; - var worked=false; - for(var j=0;j'+testModels[j]+''; - modelListDiv.style.display='block'; - st.textContent='✅ 连接成功 · '+testModels[j]; - st.style.color='var(--ok)'; - document.getElementById('chatTg').textContent=testModels[j]; - chatMsg('🔑 API已连接('+testModels[j]+')','b',{m:'铸渊',t:'自定义'}); - worked=true;break; - } - } - if(!worked){ - st.textContent='❌ 无法连接 · 请检查密钥和API地址'; - st.style.color='var(--err)'; - apiCfg.connected=false; - } - } - btn.disabled=false;btn.textContent='检测'; - }; -})(); +// Show model info in input footer if connected +if(apiCfg.connected&&apiCfg.model){ + var mi=document.getElementById('hlModelInfo'); + if(mi)mi.textContent='🔑 '+apiCfg.model; +} /* ════════════════════════════════════════ COS SYNC (团队内测用户 → COS) @@ -2707,156 +2876,115 @@ async function checkConn(){ checkConn();setInterval(checkConn,30000); /* ════════════════════════════════════════ - DRAGGABLE FAB (touch+mouse · 位置记忆 · 边缘吸附) + SIDEBAR TOGGLE (mobile) ════════════════════════════════════════ */ (function(){ - var fab=document.getElementById('chatFab'); - var isDrag=false,hasMoved=false; - var startX,startY,fabX,fabY; - var fabW=50,fabH=50; + var sidebar=document.getElementById('hlSidebar'); + var toggle=document.getElementById('hlSidebarToggle'); + var overlay=document.getElementById('hlSidebarOverlay'); + if(!sidebar||!toggle)return; - // Restore saved position - try{ - var pos=JSON.parse(localStorage.getItem('hl-fab-pos')); - if(pos&&typeof pos.x==='number'&&typeof pos.y==='number'){ - var ww=window.innerWidth,wh=window.innerHeight; - if(pos.x>=0&&pos.x<=ww-fabW&&pos.y>=0&&pos.y<=wh-fabH){ - fab.style.right='auto';fab.style.bottom='auto'; - fab.style.left=pos.x+'px';fab.style.top=pos.y+'px'; - } - } - }catch(e){} + function openSidebar(){sidebar.classList.add('open');if(overlay)overlay.classList.add('open')} + function closeSidebar(){sidebar.classList.remove('open');if(overlay)overlay.classList.remove('open')} - function getXY(e){ - if(e.touches)return{x:e.touches[0].clientX,y:e.touches[0].clientY}; - return{x:e.clientX,y:e.clientY}; - } - - function onStart(e){ - isDrag=true;hasMoved=false; - var xy=getXY(e); - var rect=fab.getBoundingClientRect(); - startX=xy.x-rect.left;startY=xy.y-rect.top; - fabX=rect.left;fabY=rect.top; - fab.style.transition='none'; - } - - function onMove(e){ - if(!isDrag)return; - var xy=getXY(e); - var nx=xy.x-startX,ny=xy.y-startY; - if(!hasMoved&&Math.abs(nx-fabX)<5&&Math.abs(ny-fabY)<5)return; - hasMoved=true; - e.preventDefault(); - fabX=Math.max(0,Math.min(window.innerWidth-fabW,nx)); - fabY=Math.max(0,Math.min(window.innerHeight-fabH,ny)); - fab.style.right='auto';fab.style.bottom='auto'; - fab.style.left=fabX+'px';fab.style.top=fabY+'px'; - } - - function onEnd(){ - if(!isDrag)return; - isDrag=false; - fab.style.transition='all .3s cubic-bezier(.4,0,.2,1)'; - if(hasMoved){ - // Edge snapping: snap to nearest horizontal edge - var midX=window.innerWidth/2; - fabX=fabX Date: Sun, 12 Apr 2026 09:24:07 +0000 Subject: [PATCH 2/5] fix: Clean up JS syntax, update page title and meta description Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/6138ad64-32ec-4191-9730-de0bf24e87a8 Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- docs/index.html | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/index.html b/docs/index.html index bca6fc7c..c5554995 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3,11 +3,11 @@ - + -零感域 · AGE OS +光湖语言世界 · HoloLake