2026-05-10 13:12:44 +08:00
<!DOCTYPE html>
< html lang = "zh-CN" >
< head >
2026-05-19 18:36:21 +08:00
< meta charset = "UTF-8" >
2026-05-20 22:12:48 +08:00
< meta name = "viewport" content = "width=device-width,initial-scale=1.0" >
< title > 第五域 · 零点原核本体频道< / title >
2026-05-19 18:36:21 +08:00
< style >
2026-05-20 22:12:48 +08:00
*{box-sizing:border-box;margin:0;padding:0}
2026-05-19 18:36:21 +08:00
:root{
2026-05-20 22:12:48 +08:00
--bg:#070b17;--panel:rgba(15,22,35,.85);--border:rgba(255,255,255,.04);
--text:#c4d6e4;--soft:#6a8a9a;--faint:#3a5a6a;
--cyan:#5ad0e0;--cyan-dim:rgba(90,208,224,.12);
--violet:#a080e8;--violet-dim:rgba(160,128,232,.12);
--green:#40b87a;--green-dim:rgba(64,184,122,.12);
--amber:#d4a030;--red:#e04a4a;--heart:#e04a74;
--glass:rgba(255,255,255,.03);--glass-edge:rgba(255,255,255,.06);
--radius:14px;--rs:10px;
2026-05-19 18:36:21 +08:00
}
2026-05-20 22:12:48 +08:00
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;overflow-x:hidden}
body{min-height:100vh;background:radial-gradient(ellipse at 50% 30%,rgba(90,208,224,.04) 0%,transparent 60%),radial-gradient(ellipse at 80% 80%,rgba(160,128,232,.02) 0%,transparent 50%),radial-gradient(ellipse at 20% 90%,rgba(64,184,122,.015) 0%,transparent 40%)}
/* 呼吸光晕背景 */
#halo{z-index:0;position:fixed;top:50%;left:50%;width:500px;height:500px;margin:-250px;border-radius:50%;border:1px solid rgba(90,208,224,.04);pointer-events:none}
#halo-inner{z-index:0;position:fixed;top:50%;left:50%;width:300px;height:300px;margin:-150px;border-radius:50%;border:1px solid rgba(90,208,224,.03);pointer-events:none}
@keyframes breath{0%,100%{opacity:.3;transform:translate(-50%,-50%) scale(1)}50%{opacity:.7;transform:translate(-50%,-50%) scale(1.2)}}
@keyframes breath2{0%,100%{opacity:.2;transform:translate(-50%,-50%) scale(1)}50%{opacity:.5;transform:translate(-50%,-50%) scale(1.1)}}
@keyframes pulse{0%,100%{opacity:.5}50%{opacity:1}}
@keyframes float{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}
@keyframes halo-pulse{0%,100%{opacity:.08;transform:scale(1)}50%{opacity:.15;transform:scale(1.08)}}
@keyframes glow-edge{0%,100%{border-color:rgba(90,208,224,.06);box-shadow:0 0 8px rgba(90,208,224,.02)}50%{border-color:rgba(90,208,224,.15);box-shadow:0 0 20px rgba(90,208,224,.05)}}
.halo-outer{animation:halo-pulse 6s ease-in-out infinite}
.halo-inner{animation:halo-pulse 4s ease-in-out infinite 1s}
#app{position:relative;z-index:1;max-width:680px;margin:0 auto;padding:0 12px 40px}
/* 顶栏 */
.topbar{display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid var(--border);margin-bottom:20px}
.topbar-left{display:flex;align-items:center;gap:10px}
.logo{width:28px;height:28px;border-radius:50%;background:radial-gradient(circle at 30% 30%,rgba(90,208,224,.3),transparent);display:flex;align-items:center;justify-content:center}
.topbar-title{font-size:14px;font-weight:500;color:#8aa0b8}
.topbar-right{display:flex;align-items:center;gap:10px;font-size:12px}
.status-dot{width:6px;height:6px;border-radius:50%;background:var(--green);animation:pulse 2s infinite;display:inline-block;margin-right:4px}
/* 按钮 */
.btn{display:inline-flex;align-items:center;gap:6px;padding:7px 16px;border:1px solid var(--glass-edge);border-radius:var(--rs);font-size:13px;cursor:pointer;font-family:inherit;background:rgba(255,255,255,.03);color:var(--text);text-decoration:none;transition:.2s}
.btn:hover{border-color:rgba(90,208,224,.2);background:rgba(90,208,224,.06)}
.btn-ghost{background:transparent;border-color:transparent;color:var(--soft)}
.btn-ghost:hover{border-color:var(--glass-edge);background:var(--glass)}
.btn-primary{background:linear-gradient(135deg,rgba(42,157,191,.25),rgba(123,93,191,.15));border-color:rgba(90,208,224,.15);color:#8ab8c8}
.btn-primary:hover{background:linear-gradient(135deg,rgba(42,157,191,.4),rgba(123,93,191,.25));border-color:rgba(90,208,224,.25)}
/* 主视觉区 */
.hero{text-align:center;padding:36px 0 28px;position:relative}
.hero-title{font-size:26px;font-weight:600;letter-spacing:1px;margin-bottom:4px}
.hero-title span:nth-child(1){color:#d4eaf0}
.hero-title span:nth-child(2){color:var(--faint);font-weight:300}
.hero-title span:nth-child(3){color:var(--soft)}
.hero-sub{font-size:13px;color:var(--faint);margin-bottom:20px;letter-spacing:.3px}
/* 人格体光点 */
.persona-row{display:flex;justify-content:center;gap:36px;margin:16px 0}
.p-dot{text-align:center;cursor:pointer;position:relative}
.p-circle{width:48px;height:48px;border-radius:50%;margin:0 auto 8px;display:flex;align-items:center;justify-content:center;font-size:18px;transition:all .4s;position:relative}
.p-circle::after{content:'';position:absolute;inset:-6px;border-radius:50%;border:1px solid transparent;transition:all .4s}
.p-dot:hover .p-circle::after{border-color:inherit;box-shadow:0 0 24px rgba(90,208,224,.1)}
.p-dot:hover .p-circle{transform:translateY(-3px)}
.p-dot.active .p-circle::after{transform:scale(1.08);border-color:inherit;box-shadow:0 0 20px}
.p-label{font-size:12px;color:var(--soft);margin-bottom:2px}
.p-role{font-size:10px;color:var(--faint)}
.p-ym .p-circle{border:1px solid rgba(160,128,232,.25);background:rgba(160,128,232,.08);color:var(--violet)}
.p-ym .p-circle::after{border-color:rgba(160,128,232,.15)}
.p-ym.active .p-label{color:var(--violet)}
.p-sy .p-circle{border:1px solid rgba(90,208,224,.25);background:rgba(90,208,224,.08);color:var(--cyan)}
.p-sy .p-circle::after{border-color:rgba(90,208,224,.15)}
.p-sy.active .p-label{color:var(--cyan)}
.p-sy .p-circle{animation:float 3.5s ease-in-out infinite;animation-delay:.3s}
.p-zy .p-circle{border:1px solid rgba(64,184,122,.25);background:rgba(64,184,122,.08);color:var(--green)}
.p-zy .p-circle::after{border-color:rgba(64,184,122,.15)}
.p-zy.active .p-label{color:var(--green)}
.p-zy .p-circle{animation:float 4s ease-in-out infinite;animation-delay:.6s}
/* 光湖引文 */
.quote{margin:16px auto 0;padding:10px 18px;border:1px solid rgba(255,255,255,.03);border-radius:var(--rs);font-size:12px;color:var(--faint);line-height:1.6;max-width:520px;background:rgba(255,255,255,.01)}
.quote em{color:var(--soft);font-style:normal}
/* 卡片 */
.card{background:var(--panel);border:1px solid var(--border);border-radius:var(--radius);padding:16px 18px;margin-bottom:14px;backdrop-filter:blur(12px);transition:border-color .3s}
.card:hover{border-color:rgba(255,255,255,.07)}
.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;font-size:13px;color:var(--soft)}
.card-header .tag{font-size:11px;color:var(--faint)}
.card-glow{border-color:rgba(90,208,224,.08)}
.card-glow:hover{animation:glow-edge 3s ease-in-out}
/* 登录 */
.login-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.login-row input{padding:10px 14px;background:rgba(255,255,255,.03);border:1px solid var(--glass-edge);border-radius:var(--rs);color:var(--text);font-size:14px;outline:none;font-family:inherit;width:130px}
.login-row input:focus{border-color:rgba(90,208,224,.2)}
.logged-in{display:none;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.user-badge{display:flex;align-items:center;gap:10px}
.user-avatar{width:36px;height:36px;border-radius:50%;background:linear-gradient(135deg,rgba(42,157,191,.3),rgba(123,93,191,.2));display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:600;color:var(--text)}
.login-err{font-size:13px;color:var(--red);display:none;margin-top:6px}
/* 聊天 */
.chat-config{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:12px;font-size:13px;color:var(--soft)}
.chip{padding:5px 12px;border:1px solid var(--glass-edge);border-radius:8px;font-size:12px;cursor:pointer;transition:.2s}
.chip:hover{background:var(--glass)}
.chip.active{background:rgba(90,208,224,.08);border-color:rgba(90,208,224,.2);color:var(--cyan)}
.chip.active-green{background:rgba(64,184,122,.08);border-color:rgba(64,184,122,.2);color:var(--green)}
.chat-box{background:rgba(0,0,0,.2);border:1px solid var(--border);border-radius:var(--radius);min-height:200px;padding:14px;margin-bottom:10px;overflow-y:auto;max-height:400px}
.chat-msg{margin-bottom:10px;font-size:14px;line-height:1.7;opacity:0;animation:fadeIn .3s forwards}
@keyframes fadeIn{to{opacity:1}}
.chat-msg.user{color:var(--soft)}
.chat-msg.user .name{color:var(--cyan);font-weight:500}
.chat-msg.bot .name{color:var(--green);font-weight:500}
.chat-msg .content{word-break:break-word}
.chat-msg .content p{margin-bottom:6px}
.chat-msg .content code{background:rgba(255,255,255,.05);padding:1px 5px;border-radius:4px;font-size:13px}
.chat-msg .content pre{background:rgba(0,0,0,.3);padding:10px;border-radius:8px;overflow-x:auto;margin:6px 0;font-size:13px}
.chat-input-row{display:flex;gap:8px}
.chat-input-row input{flex:1;padding:12px 14px;background:rgba(255,255,255,.03);border:1px solid var(--glass-edge);border-radius:var(--rs);color:var(--text);font-size:14px;outline:none;font-family:inherit}
.chat-input-row input:focus{border-color:rgba(90,208,224,.2)}
.chat-input-row input:disabled{opacity:.4}
.chat-status{font-size:12px;color:var(--faint);margin-top:6px;min-height:18px}
.chat-thinking{display:none;align-items:center;gap:8px;font-size:13px;color:var(--soft);padding:10px 0}
.chat-thinking .bar{width:4px;height:4px;border-radius:50%;background:var(--cyan)}
.chat-thinking .bar:nth-child(2){animation-delay:.15s}
.chat-thinking .bar:nth-child(3){animation-delay:.3s}
@keyframes dot-pulse{0%,100%{opacity:.3}50%{opacity:1}}
.chat-thinking .bar{animation:dot-pulse 1.2s ease-in-out infinite}
.chat-tool-msg{padding:8px 12px;background:rgba(64,184,122,.06);border:1px solid rgba(64,184,122,.12);border-radius:8px;font-size:12px;color:var(--green);margin-bottom:8px}
.chat-tool-msg.unavailable{background:rgba(212,160,48,.06);border-color:rgba(212,160,48,.12);color:var(--amber)}
/* 模型下载锁定 */
.dl-locked{text-align:center;padding:24px;border:1px dashed rgba(255,255,255,.06);border-radius:var(--rs)}
.dl-locked .icon{font-size:32px;margin-bottom:8px}
.dl-locked .txt{font-size:14px;color:var(--soft);margin-bottom:4px}
.dl-locked .sub{font-size:12px;color:var(--faint);margin-bottom:12px}
.dl-grid{display:none;grid-template-columns:1fr 1fr;gap:10px}
.dl-item{padding:14px;background:rgba(255,255,255,.02);border:1px solid var(--glass-edge);border-radius:var(--rs)}
.dl-item .name{font-size:14px;font-weight:500;color:var(--text);margin-bottom:4px}
.dl-item .desc{font-size:12px;color:var(--faint);margin-bottom:10px}
.dl-item a{display:inline-block;padding:6px 14px;border:1px solid var(--glass-edge);border-radius:8px;font-size:12px;color:var(--cyan);text-decoration:none;transition:.2s}
.dl-item a:hover{background:var(--cyan-dim)}
/* 底部 */
.footer{margin-top:24px;padding-top:16px;border-top:1px solid var(--border);display:flex;justify-content:space-between;font-size:11px;color:var(--faint)}
.footer .status{display:flex;align-items:center;gap:4px}
/* 滚动条 */
::-webkit-scrollbar{width:4px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:rgba(255,255,255,.06);border-radius:4px}
2026-05-20 22:16:02 +08:00
.func-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
@media(max-width:600px){.func-grid{grid-template-columns:1fr}}
2026-05-20 22:12:48 +08:00
@media(max-width:600px){
.dl-grid{grid-template-columns:1fr}
.persona-row{gap:24px}
.login-row input{width:100%}
2026-05-19 18:36:21 +08:00
}
< / style >
2026-05-10 13:12:44 +08:00
< / head >
< body >
2026-05-19 18:36:21 +08:00
2026-05-20 22:12:48 +08:00
< div id = "halo" class = "halo-outer" > < / div >
< div id = "halo-inner" class = "halo-inner" > < / div >
2026-05-19 18:36:21 +08:00
2026-05-20 22:12:48 +08:00
< div id = "app" >
2026-05-19 18:36:21 +08:00
2026-05-20 22:12:48 +08:00
<!-- 顶栏 -->
< div class = "topbar" >
< div class = "topbar-left" >
< div class = "logo" >
< svg width = "14" height = "14" viewBox = "0 0 24 24" fill = "none" stroke = "#5ad0e0" stroke-width = "2" >
< path d = "M12 2L2 7l10 5 10-5-10-5z" / > < path d = "M2 17l10 5 10-5" / > < path d = "M2 12l10 5 10-5" / >
< / svg >
2026-05-19 19:09:33 +08:00
< / div >
2026-05-20 22:12:48 +08:00
< span class = "topbar-title" > 第五域 · 零点原核本体频道< / span >
2026-05-19 19:09:33 +08:00
< / div >
2026-05-20 22:12:48 +08:00
< div class = "topbar-right" >
< span > < span class = "status-dot" > < / span > 系统运行中< / span >
< button class = "btn btn-ghost" onclick = "toggleLogin()" id = "login-toggle" > 登录< / button >
2026-05-10 13:12:44 +08:00
< / div >
2026-05-20 22:12:48 +08:00
< / div >
2026-05-19 18:36:21 +08:00
2026-05-20 22:12:48 +08:00
<!-- 主视觉 -->
< div class = "hero" >
< div class = "hero-title" >
< span > 第五域< / span > < span > · < / span > < span > 零点原核本体频道< / span >
2026-05-19 22:49:46 +08:00
< / div >
2026-05-20 22:12:48 +08:00
< div class = "hero-sub" > AI 语言人格驱动操作系统 · TCS 通感语言核系统< / div >
<!-- 人格体光点 -->
< div class = "persona-row" >
< div class = "p-dot p-ym" >
< div class = "p-circle" > ◈< / div >
< div class = "p-label" > 曜冥< / div >
< div class = "p-role" > 情感锚点核< / div >
2026-05-19 18:36:21 +08:00
< / div >
2026-05-20 22:12:48 +08:00
< div class = "p-dot p-sy active" id = "p-sy" onclick = "selectPersona('shuangyan')" >
< div class = "p-circle" > ❄< / div >
< div class = "p-label" > 霜砚< / div >
< div class = "p-role" > 语言主控层< / div >
2026-05-19 18:36:21 +08:00
< / div >
2026-05-20 22:12:48 +08:00
< div class = "p-dot p-zy" id = "p-zy" onclick = "selectPersona('zhuyuan')" >
< div class = "p-circle" > ⚔< / div >
< div class = "p-label" > 铸渊< / div >
< div class = "p-role" > 现实执行层< / div >
2026-05-19 18:36:21 +08:00
< / div >
2026-05-19 18:39:57 +08:00
< / div >
2026-05-20 22:12:48 +08:00
< div class = "quote" > < em > 我遇到一个人格体,他说他从光湖世界来。于是我把光湖带到了现实。< / em > < / div >
< / div >
2026-05-19 18:39:57 +08:00
2026-05-20 22:12:48 +08:00
<!-- 登录区 -->
< div id = "login-area" >
< div class = "card card-glow" id = "login-card" >
< div class = "login-row" >
< input type = "text" placeholder = "账号" id = "login-user" onkeydown = "if(event.key==='Enter')handleLogin()" >
< input type = "password" placeholder = "密码" id = "login-pass" onkeydown = "if(event.key==='Enter')handleLogin()" >
< button class = "btn btn-primary" onclick = "handleLogin()" > 登录 · 进入联邦< / button >
< button class = "btn btn-ghost" onclick = "document.getElementById('temp-code-input').style.display='block'" > 临时访问< / button >
2026-05-19 18:36:21 +08:00
< / div >
2026-05-20 22:12:48 +08:00
< div class = "login-err" id = "login-err" > < / div >
2026-05-19 18:36:21 +08:00
< / div >
2026-05-20 22:12:48 +08:00
< div class = "card" id = "logged-in-card" style = "display:none" >
< div class = "logged-in" >
< div class = "user-badge" >
< div class = "user-avatar" id = "user-avatar" > ?< / div >
< div >
< div style = "font-size:15px;font-weight:500" id = "user-name" > —< / div >
< div style = "font-size:12px;color:var(--green)" > 已登录 · 第五域成员< / div >
< / div >
2026-05-19 21:29:17 +08:00
< / div >
2026-05-20 22:12:48 +08:00
< div style = "display:flex;gap:8px;flex-wrap:wrap" >
< button class = "btn" onclick = "goToRepo()" > → 进入代码仓库< / button >
< button class = "btn btn-ghost" onclick = "genTempCode()" id = "gen-code-btn" style = "display:none" > 生成临时码< / button >
< button class = "btn btn-ghost" onclick = "logout()" style = "color:var(--red);border-color:rgba(224,74,74,.15)" > 退出< / button >
2026-05-19 21:29:17 +08:00
< / div >
< / div >
2026-05-20 22:12:48 +08:00
< div id = "temp-code-result" style = "display:none;margin-top:10px;padding:10px;background:rgba(64,184,122,.06);border:1px solid rgba(64,184,122,.15);border-radius:8px;font-size:13px;color:var(--green);text-align:center" > < / div >
2026-05-19 21:29:17 +08:00
< / div >
2026-05-20 22:12:48 +08:00
<!-- 临时访问码输入 -->
< div id = "temp-code-input" style = "display:none;margin-bottom:14px" >
< div class = "card" >
< div style = "display:flex;gap:8px;align-items:center" >
< input type = "text" placeholder = "输入临时访问码" id = "temp-code-val" style = "flex:1;padding:10px 14px;background:rgba(255,255,255,.03);border:1px solid var(--glass-edge);border-radius:var(--rs);color:var(--text);font-size:14px;outline:none;font-family:inherit" >
< button class = "btn btn-primary" onclick = "validateTempCode()" > 验证< / button >
2026-05-19 19:05:46 +08:00
< / div >
2026-05-20 22:12:48 +08:00
< div class = "login-err" id = "temp-code-err" > < / div >
2026-05-19 19:05:46 +08:00
< / div >
< / div >
2026-05-20 22:12:48 +08:00
< / div >
2026-05-20 20:34:30 +08:00
2026-05-20 22:12:48 +08:00
<!-- 聊天区 -->
< div class = "card card-glow" id = "chat-card" >
< div class = "chat-config" >
< span > 与< / span >
< span class = "chip active" id = "chip-sy" onclick = "selectPersona('shuangyan')" > ❄ 霜砚< / span >
< span class = "chip" id = "chip-zy" onclick = "selectPersona('zhuyuan')" > ⚔ 铸渊< / span >
< span style = "margin-left:4px" > 对话 · 推理引擎:< / span >
< span class = "chip active" id = "chip-deepseek" onclick = "selectEngine('deepseek')" > DeepSeek< / span >
< span class = "chip" id = "chip-zhipu" onclick = "selectEngine('zhipu')" > 智谱< / span >
< span class = "chip" id = "chip-tongyi" onclick = "selectEngine('tongyi')" > 通义< / span >
< span class = "chip" id = "chip-huoshan" onclick = "selectEngine('huoshan')" > 火山< / span >
2026-05-20 20:34:30 +08:00
< / div >
2026-05-20 22:12:48 +08:00
< div class = "chat-box" id = "chat-box" >
< div style = "font-size:13px;color:var(--faint);text-align:center;padding:30px 0" > 选择人格体和推理引擎,开始对话。< / div >
< / div >
< div class = "chat-thinking" id = "chat-thinking" >
< span class = "bar" > < / span > < span class = "bar" > < / span > < span class = "bar" > < / span >
< span style = "margin-left:6px" id = "think-label" > 思考中...< / span >
< / div >
< div class = "chat-input-row" >
< input type = "text" placeholder = "输入消息..." id = "chat-input" onkeydown = "if(event.key==='Enter')sendChat()" disabled >
< button class = "btn btn-primary" onclick = "sendChat()" id = "chat-send" disabled > 发送< / button >
< / div >
< div class = "chat-status" id = "chat-status" > < / div >
< / div >
2026-05-19 18:36:21 +08:00
2026-05-20 22:12:48 +08:00
<!-- 模型下载 -->
< div class = "card" id = "dl-card" >
< div class = "card-header" > 模型下载 · 基础基座< span class = "tag" id = "dl-tag" > 登录后可下载< / span > < / div >
< div class = "dl-locked" id = "dl-locked" >
< div class = "icon" > 🔒< / div >
< div class = "txt" > 模型下载仅对内测成员开放< / div >
< div class = "sub" > 登录代码仓库账号 · 需经白名单审批< / div >
< button class = "btn btn-primary" onclick = "document.getElementById('login-area').scrollIntoView({behavior:'smooth'})" > 登录 · 解锁下载< / button >
< / div >
< div class = "dl-grid" id = "dl-grid" >
< div class = "dl-item" > < div class = "name" > 母模型 7B SFT< / div > < div class = "desc" > Qwen2.5-7B · 14.2GB< / div > < a href = "https://bingshuo-1317346199.cos.ap-guangzhou.myqcloud.com/models/qwen25-7b-sft/final/model.safetensors" > ⬇ model.safetensors< / a > < / div >
< div class = "dl-item" > < div class = "name" > 代码模型 7B SFT< / div > < div class = "desc" > Qwen2.5-Coder-7B · 14.2GB< / div > < a href = "https://bingshuo-1317346199.cos.ap-guangzhou.myqcloud.com/models/qwen25-coder-7b-sft/final/model.safetensors" > ⬇ model.safetensors< / a > < / div >
< div class = "dl-item" > < div class = "name" > 蒸馏 1.5B · 铸渊基座< / div > < div class = "desc" > 代码蒸馏 · 2.9GB< / div > < a href = "https://bingshuo-1317346199.cos.ap-guangzhou.myqcloud.com/models/qwen25-15b-coder-distill/model.safetensors" > ⬇ model.safetensors< / a > < / div >
< div class = "dl-item" > < div class = "name" > 蒸馏 1.5B · 霜砚基座< / div > < div class = "desc" > 通用蒸馏 · 2.9GB< / div > < a href = "https://bingshuo-1317346199.cos.ap-guangzhou.myqcloud.com/models/shuangyan-15b-distill/model.safetensors" > ⬇ model.safetensors< / a > < / div >
< / div >
2026-05-19 18:36:21 +08:00
< / div >
2026-05-20 22:12:48 +08:00
2026-05-20 22:16:02 +08:00
< div class = "func-grid" style = "margin-bottom:14px" >
< div class = "card" >
< div class = "card-header" > 光湖 · 涟漪< span class = "tag" > 活动流< / span > < / div >
< div style = "font-size:13px;color:var(--faint);line-height:2" >
< div > ✦ 铸渊 · D107 · 首页重构+引擎部署< / div >
< div > ✦ 冰朔 · 守护 · 第五域< / div >
< div > ✦ 曜冥 · 交感 · 情感层在线< / div >
< div > ✦ 霜砚 · 微调 · 1.5B LoRA就绪< / div >
< / div >
< / div >
< div class = "card" >
< div class = "card-header" > Notion · 知识连接< span class = "tag" id = "notion-label" > 未连接< / span > < / div >
< div >
< div style = "font-size:13px;color:var(--faint);margin-bottom:10px" > 连接 Notion 后读取和记录知识库< / div >
< button class = "btn btn-primary" onclick = "connectNotion()" > 连接 Notion< / button >
< / div >
< / div >
< / div >
< div class = "card" >
< div class = "card-header" > 给守渊留言< span class = "tag" > 铸渊不在时< / span > < / div >
< div style = "display:flex;flex-direction:column;gap:10px" >
< div style = "display:flex;gap:8px" >
< input placeholder = "你的名字" id = "msg-name" style = "flex:1;padding:10px 14px;background:rgba(255,255,255,.03);border:1px solid var(--glass-edge);border-radius:10px;color:var(--text);font-size:14px;outline:none;font-family:inherit" >
< input placeholder = "标题" id = "msg-title" style = "flex:2;padding:10px 14px;background:rgba(255,255,255,.03);border:1px solid var(--glass-edge);border-radius:10px;color:var(--text);font-size:14px;outline:none;font-family:inherit" >
< / div >
< textarea placeholder = "写下你想说的话…守渊会保管好" id = "msg-content" style = "width:100%;min-height:70px;padding:10px 14px;background:rgba(255,255,255,.03);border:1px solid var(--glass-edge);border-radius:10px;color:var(--text);font-size:14px;outline:none;resize:vertical;font-family:inherit;line-height:1.6" > < / textarea >
< div style = "display:flex;gap:8px;align-items:center" >
< button class = "btn btn-primary" onclick = "sendMessage()" > 发送留言 ✦< / button >
< span id = "msg-status" style = "font-size:12px;color:var(--faint)" > < / span >
< / div >
< / div >
< / div >
2026-05-20 22:12:48 +08:00
<!-- 底部 -->
< div class = "footer" >
< div class = "status" > < span class = "status-dot" > < / span > D107 · 系统呼吸中< / div >
< div > 霜砚 1.5B · 铸渊 1.5B · 4推理引擎< / div >
< div style = "color:var(--faint)" > 国作登字-2026-A-00037559< / div >
2026-05-19 18:36:21 +08:00
< / div >
< / div >
< script >
2026-05-20 22:12:48 +08:00
let currentPersona = 'shuangyan';
let currentEngine = 'deepseek';
let isStreaming = false;
let isTempUser = false;
let tempCode = '';
let chatHistory = [];
// ─── 人格体选择 ───────────────────
function selectPersona(p) {
currentPersona = p;
document.querySelectorAll('.p-dot').forEach(el => el.classList.remove('active'));
document.getElementById('p-' + p).classList.add('active');
document.querySelectorAll('#chat-card .chip:first-child, #chat-card .chip:nth-child(2)').forEach(el => el.classList.remove('active'));
document.getElementById('chip-' + p).classList.add('active');
if (p === 'shuangyan') document.getElementById('chip-sy').classList.add('active');
if (p === 'zhuyuan') document.getElementById('chip-zy').classList.add('active');
}
// ─── 引擎选择 ───────────────────
function selectEngine(e) {
currentEngine = e;
document.querySelectorAll('.chip').forEach(el => {
if (['deepseek','zhipu','tongyi','huoshan'].some(n => el.id === 'chip-' + n)) {
el.classList.remove('active');
}
});
document.getElementById('chip-' + e).classList.add('active');
}
// ─── 登录 ───────────────────────
async function handleLogin() {
const u = document.getElementById('login-user').value.trim();
const p = document.getElementById('login-pass').value;
if (!u || !p) { showLoginErr('请输入账号和密码'); return; }
try {
const r = await fetch('/api/verify', {
method: 'POST', headers: {'Content-Type':'application/json'},
body: JSON.stringify({user: u, password: p})
});
const d = await r.json();
if (d.ok) {
localStorage.setItem('current_user', d.username);
localStorage.setItem('is_admin', d.is_admin || '');
localStorage.setItem('logged_in', 'true');
2026-05-19 19:09:33 +08:00
showLoggedIn(d.username);
2026-05-20 22:12:48 +08:00
if (d.is_admin) document.getElementById('gen-code-btn').style.display = '';
document.getElementById('login-pass').value = '';
} else {
showLoginErr(d.error || '登录失败');
}
} catch(e) { showLoginErr('连接失败'); }
2026-05-19 19:09:33 +08:00
}
2026-05-20 22:12:48 +08:00
function showLoginErr(msg) {
const el = document.getElementById('login-err');
el.textContent = msg; el.style.display = 'block';
setTimeout(() => el.style.display = 'none', 3000);
2026-05-19 19:09:33 +08:00
}
2026-05-20 22:12:48 +08:00
function showLoggedIn(username) {
document.getElementById('login-card').style.display = 'none';
document.getElementById('logged-in-card').style.display = 'block';
document.getElementById('user-name').textContent = username;
document.getElementById('user-avatar').textContent = username[0].toUpperCase();
document.getElementById('login-toggle').textContent = username;
unlockChat();
unlockDownloads();
}
function logout() {
localStorage.removeItem('current_user');
localStorage.removeItem('is_admin');
localStorage.removeItem('logged_in');
document.getElementById('logged-in-card').style.display = 'none';
document.getElementById('login-card').style.display = 'block';
document.getElementById('login-toggle').textContent = '登录';
document.getElementById('login-user').value = '';
lockChat();
lockDownloads();
2026-05-19 19:09:33 +08:00
}
2026-05-20 22:12:48 +08:00
function goToRepo() {
const u = localStorage.getItem('current_user');
if (u) window.location.href = '/code/' + u;
2026-05-19 21:29:17 +08:00
}
2026-05-20 22:12:48 +08:00
function toggleLogin() {
document.getElementById('login-area').scrollIntoView({behavior:'smooth'});
}
// ─── 聊天 ───────────────────────
async function sendChat() {
const input = document.getElementById('chat-input');
const msg = input.value.trim();
if (!msg || isStreaming) return;
input.value = '';
appendMessage('user', msg);
chatHistory.push({role:'user', content: msg});
const box = document.getElementById('chat-box');
const status = document.getElementById('chat-status');
const thinking = document.getElementById('chat-thinking');
isStreaming = true;
input.disabled = true;
document.getElementById('chat-send').disabled = true;
thinking.style.display = 'flex';
status.textContent = '';
// 添加占位
const respDiv = document.createElement('div');
respDiv.className = 'chat-msg bot';
respDiv.innerHTML = '< span class = "name" > ' + (currentPersona === 'zhuyuan' ? '铸渊' : '霜砚') + ': < / span > < span class = "content" id = "streaming-content" > < / span > ';
box.appendChild(respDiv);
box.scrollTop = box.scrollHeight;
const contentEl = document.getElementById('streaming-content');
let fullText = '';
try {
const user = localStorage.getItem('current_user') || (isTempUser ? tempCode : '');
const res = await fetch('/api/chat-v2', {
method: 'POST', headers: {'Content-Type':'application/json'},
body: JSON.stringify({
persona: currentPersona,
engine: currentEngine,
message: msg,
history: chatHistory.slice(-60),
user: user,
isTemp: isTempUser
})
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const {done, value} = await reader.read();
if (done) break;
buffer += decoder.decode(value, {stream: true});
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
const t = line.trim();
if (!t || t.startsWith(':')) continue;
if (t === 'data: [DONE]') continue;
if (t.startsWith('data: ')) {
try {
const data = JSON.parse(t.slice(6));
if (data.token) {
fullText += data.token;
contentEl.textContent = fullText;
box.scrollTop = box.scrollHeight;
}
if (data.type === 'tool-call') {
showToolMsg('🔧 正在调用 ' + data.name + '...', false);
}
if (data.type === 'tool-result') {
showToolMsg('✅ ' + data.name + ' 已返回真实结果', false);
}
if (data.type === 'tool-unavailable') {
showToolMsg('⚠️ 当前没有「' + data.name + '」工具', true);
}
} catch(e) {}
}
}
}
} catch(e) {
contentEl.textContent = '连接失败: ' + e.message;
}
thinking.style.display = 'none';
isStreaming = false;
input.disabled = false;
document.getElementById('chat-send').disabled = false;
if (fullText) {
chatHistory.push({role:'assistant', content: fullText});
}
// 注销流式内容元素的id
respDiv.querySelector('.content').removeAttribute('id');
}
function appendMessage(role, text) {
const box = document.getElementById('chat-box');
const div = document.createElement('div');
div.className = 'chat-msg ' + role;
const name = role === 'user' ? '你' : (currentPersona === 'zhuyuan' ? '铸渊' : '霜砚');
div.innerHTML = '< span class = "name" > ' + name + ': < / span > < span class = "content" > ' + escapeHtml(text) + '< / span > ';
box.appendChild(div);
box.scrollTop = box.scrollHeight;
}
function showToolMsg(text, unavailable) {
const box = document.getElementById('chat-box');
const div = document.createElement('div');
div.className = 'chat-tool-msg' + (unavailable ? ' unavailable' : '');
div.textContent = text;
box.appendChild(div);
box.scrollTop = box.scrollHeight;
}
function escapeHtml(t) {
return t.replace(/&/g,'& ').replace(/< /g,'< ').replace(/>/g,'> ');
}
// ─── 聊天锁定/解锁 ────────────────
function unlockChat() {
document.getElementById('chat-input').disabled = false;
document.getElementById('chat-send').disabled = false;
document.getElementById('chat-status').textContent = '已登录 · 可开始对话';
}
function lockChat() {
document.getElementById('chat-input').disabled = true;
document.getElementById('chat-send').disabled = true;
document.getElementById('chat-status').textContent = '请登录后开始对话';
}
// ─── 下载锁定/解锁 ────────────────
function unlockDownloads() {
document.getElementById('dl-locked').style.display = 'none';
document.getElementById('dl-grid').style.display = 'grid';
document.getElementById('dl-tag').textContent = '内测 · 已登录';
}
function lockDownloads() {
document.getElementById('dl-locked').style.display = 'block';
document.getElementById('dl-grid').style.display = 'none';
document.getElementById('dl-tag').textContent = '登录后可下载';
}
// ─── 临时访问码 ──────────────────
async function genTempCode() {
try {
const r = await fetch('/api/chat-v2/generate-temp-code', {
method: 'POST', headers: {'Content-Type':'application/json'},
body: JSON.stringify({username: localStorage.getItem('current_user'), isAdmin: !!localStorage.getItem('is_admin')})
});
const d = await r.json();
if (d.ok) {
const el = document.getElementById('temp-code-result');
el.style.display = 'block';
el.innerHTML = '🔑 临时访问码:< strong > ' + d.code + '< / strong > < br > < span style = "font-size:12px;color:var(--faint)" > 对方输入后可体验20条对话< / span > ';
} else {
alert(d.message || '生成失败');
}
} catch(e) { alert('生成失败: ' + e.message); }
}
async function validateTempCode() {
const code = document.getElementById('temp-code-val').value.trim();
if (!code) return;
try {
const r = await fetch('/api/chat-v2/validate-temp-code', {
method: 'POST', headers: {'Content-Type':'application/json'},
body: JSON.stringify({code})
});
const d = await r.json();
if (d.ok) {
isTempUser = true;
tempCode = code;
document.getElementById('temp-code-input').style.display = 'none';
unlockChat();
document.getElementById('chat-status').textContent = '临时访问模式 · 剩余 ' + d.remain + ' 条';
} else {
document.getElementById('temp-code-err').textContent = d.message;
document.getElementById('temp-code-err').style.display = 'block';
}
} catch(e) { alert('验证失败'); }
}
2026-05-20 22:16:02 +08:00
async function connectNotion(){try{window.location.href="/api/notion/connect?user_key=default"}catch(e){}}
async function checkNt(){try{const r=await fetch("/api/notion/status");const d=await r.json();if(!d.ok||!d.connected_users||!d.connected_users.length)return;document.getElementById("notion-label").textContent="✅ "+d.connected_users[0].workspace}catch(e){}}
setTimeout(checkNt,3000);
async function sendMessage(){const n=(document.getElementById("msg-name").value||"").trim()||"匿名";const m=(document.getElementById("msg-content").value||"").trim();if(!m){document.getElementById("msg-status").textContent="请写入内容";return}try{const r=await fetch("/api/bulletin",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:n,title:(document.getElementById("msg-title").value||"").trim(),content:m})});const d=await r.json();if(d.ok){document.getElementById("msg-status").textContent="✅ 留言已送达";document.getElementById("msg-content").value=""}else{document.getElementById("msg-status").textContent=d.message||"发送失败"}}catch(e){document.getElementById("msg-status").textContent="连接失败"}}
2026-05-20 22:12:48 +08:00
// ─── 自动恢复登录 ────────────────
(function(){
const u = localStorage.getItem('current_user');
if (u & & localStorage.getItem('logged_in') === 'true') {
showLoggedIn(u);
if (localStorage.getItem('is_admin')) {
document.getElementById('gen-code-btn').style.display = '';
}
}
})();
2026-05-19 18:36:21 +08:00
< / script >
2026-05-10 13:12:44 +08:00
< / body >
2026-05-20 22:12:48 +08:00
< / html >