-
-
-
-
+
+
+
+
+
👤
+ 无需 API 密钥,直接体验铸渊助手的基本功能。
+ 可查看团队状态面板,AI 回答功能受限。
-
⚠️ 请输入 API 密钥
-
+
-
-
👤 身份识别
-
-
-
+
+
+
🔒 API 密钥仅本次会话有效,关闭标签页即自动清除
+
+
+
- 选择你的身份,铸渊将开放对应权限面板
+ 选择你的开发者编号,系统将验证身份并开放对应权限
-
-
-
-
用于人格体记忆绑定,可留空
+
+
+
+
+
+ 输入你的 API 提供商端点地址(OpenAI 兼容格式)
+
+
+
+
+
+
+
⚠️ 请输入 API 密钥
+
+
+
+
+
+ 输入端点和密钥后,点击「🔍 检测模型」自动获取可用模型列表
+
+
+
-
-
没有 API 密钥?使用演示模式(功能有限)
@@ -513,27 +517,12 @@ footer{padding:12px 18px 16px;background:var(--s1);border-top:1px solid var(--bo
-
-
-
-
-
+
-
+
-
- 自定义模式:直接输入你的服务商支持的任意模型名称
@@ -569,18 +558,18 @@ footer{padding:12px 18px 16px;background:var(--s1);border-top:1px solid var(--bo
关于铸渊助手
-
版本v4.0
+
版本v5.0
唤醒协议v1.0
大脑路径.github/brain/
使用说明
- 1. 输入你的 AI 模型 API 密钥并保存
+ 1. 输入你的 API 端点和密钥,点击检测模型
2. 说「我是冰朔」触发铸渊唤醒序列
3. 铸渊自动切换 💬 对话 / 🔨 构建 / 📋 审查 / 🧠 大脑 模式
4. 点 ⬇️ 下载单文件,放桌面直接打开使用
- 5. 支持 OpenAI · DeepSeek · Kimi · 智谱 · 任意兼容接口
+ 5. 支持任意 OpenAI 兼容接口(输入端点 + 密钥即可)
⚠️ 危险操作
@@ -612,10 +601,10 @@ footer{padding:12px 18px 16px;background:var(--s1);border-top:1px solid var(--bo
🚀 怎么开始用
- 打开链接 https://qinfendebingshuo.github.io/guanghulab/
- - 下拉菜单选择你是谁(冰朔 / 肥猫 / 桔子 / 开发者名字)
- - 填入你的 API Key 并点「🔍 自动检测」,系统将自动识别提供商和可用模型
- - 点「开始对话」,铸渊会针对你的身份打招呼
- - 直接用聊天的方式问铸渊任何问题
+ - 选择「👤 访客模式」直接体验,或「🔑 编号登录」开发者身份登录
+ - 编号登录:选择你的身份,输入 API 端点 和 API 密钥,点「🔍 检测模型」
+ - 系统自动检测可用模型列表,选择你要用的模型
+ - 点「开始对话」,铸渊会针对你的身份打招呼
@@ -623,11 +612,11 @@ footer{padding:12px 18px 16px;background:var(--s1);border-top:1px solid var(--bo
🔑 从哪里获取 API Key?
推荐用云雾 AI(团队共用)
-
找冰朔或肥猫获取团队 Key。填入后选「☁️ 云雾 AI(团队推荐)」提供商即可直接使用。
+
找冰朔或肥猫获取团队 Key 和端点地址,输入后点「🔍 检测模型」即可使用。
-
没有 Key?用演示模式
-
点「演示模式」也能查看团队进度面板(🦁 指挥台),只是 AI 回答功能受限。
+
没有 Key?用访客模式
+
登录页选择「👤 访客模式」进入演示,可查看团队进度面板(🦁 指挥台),AI 回答功能受限。
@@ -720,16 +709,15 @@ const ROLE_MAP = {
'Awen': {role:'dev', title:'通知中心开发', emoji:'💻', badgeCls:'rb-dev', devId:'DEV-012'},
};
-const PROVS = {
- proxy: {base:'/api', mdls:['deepseek-chat','gpt-4o','moonshot-v1-8k','glm-4'],isProxy:true},
- yunwu: {base:'https://api.yunwu.ai/v1', mdls:['gpt-4o','gpt-4o-mini','claude-3-5-sonnet-20241022','deepseek-chat','gemini-1.5-pro']},
- openai: {base:'https://api.openai.com/v1', mdls:['gpt-4o','gpt-4o-mini','gpt-4-turbo','gpt-3.5-turbo']},
- gemini: {base:'https://generativelanguage.googleapis.com/v1beta/openai', mdls:['gemini-2.0-flash','gemini-2.0-flash-lite','gemini-1.5-pro','gemini-1.5-flash']},
- deepseek: {base:'https://api.deepseek.com/v1', mdls:['deepseek-chat','deepseek-reasoner']},
- moonshot: {base:'https://api.moonshot.cn/v1', mdls:['moonshot-v1-8k','moonshot-v1-32k','moonshot-v1-128k']},
- zhipu: {base:'https://open.bigmodel.cn/api/paas/v4', mdls:['glm-4','glm-4-flash','glm-4-air']},
- custom: {base:'', mdls:['gpt-4o']},
-};
+// Known API endpoints for fallback auto-detect (when user doesn't provide endpoint)
+const KNOWN_ENDPOINTS = [
+ {label:'云雾 AI', base:'https://api.yunwu.ai/v1'},
+ {label:'OpenAI', base:'https://api.openai.com/v1'},
+ {label:'Google Gemini',base:'https://generativelanguage.googleapis.com/v1beta/openai'},
+ {label:'DeepSeek', base:'https://api.deepseek.com/v1'},
+ {label:'Moonshot', base:'https://api.moonshot.cn/v1'},
+ {label:'智谱 AI', base:'https://open.bigmodel.cn/api/paas/v4'},
+];
const MODES = {
chat: {e:'💬',l:'对话模式', c:'var(--mc)'},
@@ -755,16 +743,11 @@ const FB_BRAIN = {
// ═══════════════════════════════════════════════════════
// STATE
// ═══════════════════════════════════════════════════════
-const _initProv = ls('zy_prov')||'yunwu';
-const _initBase = _initProv === 'custom'
- ? (ls('zy_base')||'')
- : (PROVS[_initProv]?.base||'https://api.yunwu.ai/v1');
-
const A = {
key: sessionStorage.getItem('zy_key')||'',
- base: _initBase,
- mdl: ls('zy_mdl')||DEFAULT_MDL,
- prov: _initProv,
+ base: ls('zy_base')||'',
+ mdl: ls('zy_mdl')||'',
+ prov: 'custom',
demo: false,
brain: null,
routing: null,
@@ -1101,20 +1084,17 @@ async function boot(){
if(new URLSearchParams(location.search).get('reset')==='1'){
RESET_KEYS.forEach(k => localStorage.removeItem(k));
sessionStorage.removeItem('zy_key');
- A.key=''; A.base=PROVS['yunwu'].base; A.mdl=DEFAULT_MDL; A.prov='yunwu'; A.demo=false;
+ A.key=''; A.base=''; A.mdl=''; A.prov='custom'; A.demo=false;
A.userName=''; A.ghUser=''; A.role='guest';
history.replaceState(null,'',location.pathname);
}
localStorage.removeItem('zy_key');
initSetupUI();
if(A.userName) A.userMeta = ROLE_MAP[A.userName]||null;
- const isProxy = PROVS[A.prov]?.isProxy;
- if(A.key||A.demo||isProxy){
+ if(A.key||A.demo){
showApp();
} else {
if(A.userName) document.getElementById('suid').value=A.userName;
- if(A.ghUser) document.getElementById('sghuser').value=A.ghUser;
- updateIdPreview();
document.getElementById('setup').style.display='flex';
}
}
@@ -1122,7 +1102,7 @@ async function boot(){
function showApp(){
document.getElementById('setup').style.display='none';
document.getElementById('app').classList.add('on');
- document.getElementById('hmdl').textContent = A.mdl;
+ document.getElementById('hmdl').textContent = A.mdl||'—';
document.getElementById('bbdemo').style.display = A.demo?'inline':'none';
applyIdentityUI();
updateLeftSidebar();
@@ -1147,57 +1127,30 @@ function showApp(){
// SETUP FORM
// ═══════════════════════════════════════════════════════
function initSetupUI(){
- const pv = A.prov||'yunwu';
- document.getElementById('sp').value = pv;
- const isCustom = pv==='custom';
- document.getElementById('sm').style.display = isCustom?'none':'block';
- document.getElementById('sm-cust').style.display = isCustom?'block':'none';
- document.getElementById('sm-cust-hint').style.display= isCustom?'block':'none';
- if(isCustom){
- document.getElementById('sm-cust').value = A.mdl||DEFAULT_MDL;
- document.getElementById('sep-g').style.display='block';
- document.getElementById('sep').value = A.base;
- } else {
- fillModels('sm', pv, A.mdl);
+ if(A.base){
+ const sepEl = document.getElementById('sep');
+ if(sepEl) sepEl.value = A.base;
+ }
+ if(A.userName){
+ const suidEl = document.getElementById('suid');
+ if(suidEl) suidEl.value = A.userName;
+ updateIdPreview();
}
}
-function onProv(pv,ctx){
- const mdlSel = ctx==='s'?'sm':'cm';
- const mdlCust = ctx==='s'?'sm-cust':'cm-cust';
- const mdlHint = ctx==='s'?'sm-cust-hint':'cm-cust-hint';
- const epGrp = ctx==='s'?'sep-g':'cep-g';
- const epInp = ctx==='s'?'sep':'cep';
- const keyInp = ctx==='s'?'sk':'ck';
- const cur = ctx==='s'? A.mdl : document.getElementById('cm')?.value;
- const isCustom = pv==='custom';
- const isProxy = PROVS[pv]?.isProxy;
- document.getElementById(mdlSel).style.display = isCustom?'none':'block';
- document.getElementById(mdlCust).style.display = isCustom?'block':'none';
- document.getElementById(mdlHint).style.display = isCustom?'block':'none';
- if(isCustom){
- const custInp = document.getElementById(mdlCust);
- if(custInp && !custInp.value) custInp.value = cur||DEFAULT_MDL;
+function switchLoginMode(mode){
+ document.querySelectorAll('.login-tab').forEach(function(t){t.classList.remove('active');});
+ document.querySelectorAll('.login-mode').forEach(function(m){m.classList.remove('active');});
+ if(mode==='guest'){
+ document.querySelector('.login-tab:first-child').classList.add('active');
+ document.getElementById('login-guest').classList.add('active');
} else {
- fillModels(mdlSel, pv, cur);
+ document.querySelector('.login-tab:last-child').classList.add('active');
+ document.getElementById('login-dev').classList.add('active');
}
- document.getElementById(epGrp).style.display = isCustom?'block':'none';
- if(!isCustom){
- const ep = document.getElementById(epInp);
- if(ep) ep.value = PROVS[pv]?.base||'';
- }
- // Proxy mode: API key is optional (managed server-side)
- const ki = document.getElementById(keyInp);
- if(ki) ki.placeholder = isProxy ? '后端代理模式(无需密钥)' : (ctx==='s'?'粘贴任意 API 密钥,点击右侧按钮自动识别提供商和模型':'留空 = 保持当前密钥不变;粘贴新密钥即替换');
}
-function fillModels(selId, pv, cur){
- const sel = document.getElementById(selId);
- if(!sel) return;
- const mdls = PROVS[pv]?.mdls||[DEFAULT_MDL];
- sel.innerHTML = mdls.map(m=>'
').join('');
- if(cur && mdls.includes(cur)) sel.value=cur;
-}
+// (Provider switching removed — single custom endpoint mode)
// ═══════════════════════════════════════════════════════
// AUTO-DETECT PROVIDER & MODELS
@@ -1206,6 +1159,7 @@ async function autoDetectAPI(ctx){
const keyEl = document.getElementById(ctx==='s'?'sk':'ck');
const statusEl = document.getElementById(ctx==='s'?'sdet-status':'cdet-status');
const btnEl = document.getElementById(ctx==='s'?'sdet-btn':'cdet-btn');
+ const mdlSel = document.getElementById(ctx==='s'?'sm':'cm');
const key = keyEl.value.trim();
if(!key){
@@ -1213,98 +1167,91 @@ async function autoDetectAPI(ctx){
return;
}
+ // Build list of endpoints to probe: user's endpoint first, then known fallbacks
+ const userBase = (document.getElementById(ctx==='s'?'sep':'cep')?.value||'').trim();
const candidates = [];
- const customBase = (document.getElementById(ctx==='s'?'sep':'cep')?.value||'').trim();
- if(customBase) candidates.push({pv:'custom', base:customBase});
- for(const [pv, cfg] of Object.entries(PROVS)){
- if(pv!=='custom' && cfg.base) candidates.push({pv, base:cfg.base});
+ if(userBase) candidates.push({label:userBase, base:userBase});
+ for(const ep of KNOWN_ENDPOINTS){
+ if(ep.base !== userBase) candidates.push(ep);
}
btnEl.disabled = true;
btnEl.textContent = '⏳ 检测中…';
- statusEl.innerHTML = '
🔍 正在自动探测兼容提供商…';
+ statusEl.innerHTML = '
🔍 正在探测可用模型…';
let matched = false;
- for(const {pv, base} of candidates){
- statusEl.innerHTML = '
🔍 探测 '+(pv === 'custom' ? base : pv)+'…';
+ for(const {label, base} of candidates){
+ statusEl.innerHTML = '
🔍 探测 '+esc(label)+'…';
try{
const ctrl = new AbortController();
- const tid = setTimeout(()=>ctrl.abort(), PROBE_TIMEOUT_MS);
+ const tid = setTimeout(function(){ctrl.abort();}, PROBE_TIMEOUT_MS);
const res = await fetch(base+'/models',{
headers:{'Authorization':'Bearer '+key},
signal: ctrl.signal,
});
clearTimeout(tid);
if(res.ok){
- const data = await res.json();
- const mdls = (data.data||[]).map(m=>m.id).filter(Boolean).sort();
+ const data = await res.json();
+ const mdls = (data.data||[]).map(function(m){return m.id;}).filter(Boolean).sort();
if(!mdls.length) continue;
- const provSel = document.getElementById(ctx==='s'?'sp':'cp');
- if(provSel) provSel.value = pv;
- onProv(pv, ctx);
+ // Fill endpoint field with matched endpoint
+ const epEl = document.getElementById(ctx==='s'?'sep':'cep');
+ if(epEl) epEl.value = base;
- const mdlSel = document.getElementById(ctx==='s'?'sm':'cm');
- const mdlCust = document.getElementById(ctx==='s'?'sm-cust':'cm-cust');
- const mdlHint = document.getElementById(ctx==='s'?'sm-cust-hint':'cm-cust-hint');
+ // Fill model dropdown with detected models
if(mdlSel){
- mdlSel.innerHTML = mdls.map(m=>'
').join('');
- mdlSel.style.display = 'block';
- }
- if(mdlCust) mdlCust.style.display='none';
- if(mdlHint) mdlHint.style.display='none';
-
- if(pv==='custom' && ctx==='s'){
- document.getElementById('sep-g').style.display='block';
- document.getElementById('sep').value = customBase;
- } else if(pv==='custom' && ctx==='c'){
- document.getElementById('cep-g').style.display='block';
- document.getElementById('cep').value = customBase;
+ mdlSel.innerHTML = mdls.map(function(m){return '
';}).join('');
+ mdlSel.disabled = false;
}
- const label = PROVS[pv]?.base ? pv : customBase;
- statusEl.innerHTML = '
✅ 检测成功('+label+')· 共发现 '+mdls.length+' 个可用模型';
+ statusEl.innerHTML = '
✅ 检测成功('+esc(label)+')· 发现 '+mdls.length+' 个可用模型';
matched = true;
break;
}
- }catch(e){ console.debug('autoDetect probe failed:', pv, e.message); }
+ }catch(e){ console.debug('autoDetect probe failed:', label, e.message); }
}
if(!matched){
- statusEl.innerHTML = '
❌ 未能自动匹配,请手动选择提供商和模型后保存';
+ statusEl.innerHTML = '
❌ 未能检测到可用模型,请检查端点地址和密钥是否正确';
}
btnEl.disabled = false;
- btnEl.textContent = '🔍 自动检测';
+ btnEl.textContent = '🔍 检测模型';
}
function doSetup(){
- const pv = document.getElementById('sp').value;
- const isProxy = PROVS[pv]?.isProxy;
- const k = document.getElementById('sk').value.trim();
+ const un = document.getElementById('suid').value;
+ const k = document.getElementById('sk').value.trim();
+ const base = (document.getElementById('sep')?.value||'').trim();
+ const md = document.getElementById('sm').value;
const errEl = document.getElementById('sk-err');
- // Proxy mode doesn't require an API key
- if(!k && !isProxy){errEl.style.display='block';return;}
+
+ if(!un){
+ alert('请选择你的开发者身份');
+ return;
+ }
+ if(!k){errEl.style.display='block';return;}
errEl.style.display='none';
- const md = pv==='custom'
- ? ((document.getElementById('sm-cust')?.value||'').trim()||DEFAULT_MDL)
- : document.getElementById('sm').value;
- let base = PROVS[pv]?.base||'';
- if(pv==='custom') base=(document.getElementById('sep')?.value||'').trim()||base;
- A.key=k; A.base=base; A.mdl=md; A.prov=pv; A.demo=false;
- if(k) sessionStorage.setItem('zy_key', k);
- lss('zy_base',base); lss('zy_mdl',md); lss('zy_prov',pv);
- const un = document.getElementById('suid').value;
- const gh = (document.getElementById('sghuser')?.value||'').trim();
- setIdentity(un, gh);
+ if(!base){
+ alert('请输入 API 端点 URL');
+ return;
+ }
+ if(!md){
+ alert('请先点击「🔍 检测模型」检测可用模型,然后选择一个模型');
+ return;
+ }
+
+ A.key=k; A.base=base; A.mdl=md; A.prov='custom'; A.demo=false;
+ sessionStorage.setItem('zy_key', k);
+ lss('zy_base',base); lss('zy_mdl',md); lss('zy_prov','custom');
+ setIdentity(un, '');
showApp();
}
function doDemo(){
- A.demo=true; A.key='';
- const un = document.getElementById('suid').value;
- const gh = (document.getElementById('sghuser')?.value||'').trim();
- setIdentity(un, gh);
+ A.demo=true; A.key=''; A.prov='custom';
+ setIdentity('', '');
showApp();
}
@@ -1312,18 +1259,14 @@ function doDemo(){
// SETTINGS PANEL
// ═══════════════════════════════════════════════════════
function initSettingsPanel(){
- const pv = A.prov||'yunwu';
- document.getElementById('cp').value = pv;
- const isCustom = pv==='custom';
- document.getElementById('cm').style.display = isCustom?'none':'block';
- document.getElementById('cm-cust').style.display = isCustom?'block':'none';
- document.getElementById('cm-cust-hint').style.display= isCustom?'block':'none';
- if(isCustom){
- document.getElementById('cm-cust').value = A.mdl||DEFAULT_MDL;
- document.getElementById('cep-g').style.display='block';
- document.getElementById('cep').value = A.base;
- } else {
- fillModels('cm', pv, A.mdl);
+ const cepEl = document.getElementById('cep');
+ if(cepEl) cepEl.value = A.base||'';
+ const cmEl = document.getElementById('cm');
+ if(cmEl && A.mdl){
+ if(!cmEl.querySelector('option[value="'+A.mdl+'"]')){
+ cmEl.innerHTML = '
';
+ }
+ cmEl.value = A.mdl;
}
document.getElementById('ck').value = '';
const hint = document.getElementById('ck-hint');
@@ -1337,17 +1280,13 @@ function initSettingsPanel(){
}
function saveSet(){
- const pv = document.getElementById('cp').value;
- const md = pv==='custom'
- ? ((document.getElementById('cm-cust')?.value||'').trim()||A.mdl||DEFAULT_MDL)
- : document.getElementById('cm').value;
+ const base = (document.getElementById('cep')?.value||'').trim()||A.base;
+ const md = document.getElementById('cm')?.value||A.mdl;
const raw = document.getElementById('ck').value.trim();
const k = raw || A.key;
- let base = PROVS[pv]?.base||'';
- if(pv==='custom') base=(document.getElementById('cep').value.trim())||base;
- A.key=k; A.base=base; A.mdl=md; A.prov=pv; A.demo=!k;
+ A.key=k; A.base=base; A.mdl=md; A.prov='custom'; A.demo=!k;
if(k){ sessionStorage.setItem('zy_key', k); } else { sessionStorage.removeItem('zy_key'); }
- lss('zy_base',base); lss('zy_mdl',md); lss('zy_prov',pv);
+ lss('zy_base',base); lss('zy_mdl',md); lss('zy_prov','custom');
const un = document.getElementById('cuid')?.value||A.userName;
const gh = document.getElementById('cghuser')?.value?.trim()||A.ghUser;
setIdentity(un, gh);
@@ -1580,22 +1519,18 @@ async function streamReply(txt){
updSendBtn();
const el=addStreamBubble();
try{
- const isProxy = PROVS[A.prov]?.isProxy;
- const url = isProxy ? (A.base+'/chat') : (A.base+'/chat/completions');
+ const url = A.base+'/chat/completions';
const headers = {'Content-Type':'application/json'};
- if(!isProxy && A.key) headers['Authorization'] = 'Bearer '+A.key;
+ if(A.key) headers['Authorization'] = 'Bearer '+A.key;
const allMsgs = [{role:'system',content:sysPrompt()},...A.msgs];
- const reqBody = isProxy
- ? {model:A.mdl, messages:allMsgs, stream:true, temperature:0.8, max_tokens:2000}
- : {model:A.mdl, messages:allMsgs, stream:true, temperature:0.8, max_tokens:2000};
+ const reqBody = {model:A.mdl, messages:allMsgs, stream:true, temperature:0.8, max_tokens:2000};
const res=await fetch(url,{
method:'POST',
headers:headers,
body:JSON.stringify(reqBody),
});
if(!res.ok){
- const provLabel = A.prov==='custom' ? A.base : (A.prov+'('+A.base+')');
- let em='['+provLabel+'] 返回错误 '+res.status;
+ let em='['+esc(A.base)+'] 返回错误 '+res.status;
let isAuthErr = (res.status===401||res.status===403);
try{const e=await res.json();em=e.error?.message||em;}catch(_){}
const err = new Error(em);
@@ -1671,7 +1606,7 @@ function demoRespond(t){
if(/协调|阻塞|卡住|waiting/.test(s)) return buildBlockedStatus();
if(/怎么唤醒|入口|在哪/.test(s)) return '铸渊有三个入口:
① 铸渊聊天室(当前页面)直接在这里说话,常见问题即刻回答。
② GitHub Copilot Chat(Agent 模式)打开仓库 → 右上角 ✨ 图标 → 选 Agent → 输入「我是冰朔」
③ 下载到桌面点击 ⬇️ 按钮下载 HTML 文件,放到桌面,双击打开,接入 API 密钥即可随时使用。';
if(/介绍|是什么|你是谁/.test(s)) return '🌀
铸渊(Zhùyuān)我是 HoloLake 光湖系统的代码守护人格体,运行在 GitHub Copilot Agent 模式下。
我的职责:
• 📊 监控 HLI 接口覆盖率
• 🔨 协助开发者构建接口
• 📋 代码审查与质量把关
• 🧠 维护大脑记忆库
• 🦁 支持总控肥猫指挥落地
• 🌱 作为成长人格体持续进化';
- return '我收到了你的消息。由于当前是演示模式,无法给出真实 AI 回答。
请在
⚙️ 设置 中输入你的 API 密钥(支持 OpenAI / DeepSeek / Kimi / 智谱),然后你就可以得到铸渊真正的回答了。';
+ return '我收到了你的消息。由于当前是演示模式,无法给出真实 AI 回答。
请在
⚙️ 设置 中输入你的 API 端点和密钥,检测模型后即可获得铸渊真正的回答。';
}
function buildCovTable(){