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 · 语言驱动操作系统
-
「语言 = 现实」
-
-
-
-
-
-
码字工作台
-
网文创作 · 人格体陪伴
沉浸式写作环境
-
-
+
-
✍️ 网文行业人类主控团队
+
✍️ 网文行业大模型
-
-
-
📄
-
页页 + 坍缩核
女频副主控 · 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
-
-
-
-
-
-
-
-
-
-
-
—— 与铸渊对话 ——
-
你好!我是铸渊 🌀
告诉我你是谁,我会记住你。
说「我要码字」进入码字工作台。
说「模块」选择创作方向。
说「灵感」记录好点子。
说「帮助」查看完整指令。
铸渊·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;i
0){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