-
-
+
+
+
+
-
🔒 密钥仅本次会话有效,关闭标签页自动清除
+
自动检测网络环境,连接服务器代理获取可用模型(无需密钥)
+
+
+
+
+
+
+
+
+ 🔧 自定义 API(使用自己的密钥)
+
+
+
身份设置
@@ -665,11 +690,11 @@ footer{padding:12px 18px 16px;padding-bottom:max(16px,env(safe-area-inset-bottom
使用说明
- 1. 输入你的 API 端点和密钥,点击检测模型
- 2. 铸渊自动切换 💬 对话 / 🔨 构建 / 📋 审查 / 🧠 大脑 模式
- 3. 支持上传图片和文件(点击 📎 按钮或拖拽到对话区域)
- 4. 点 ⬇️ 下载单文件,放桌面直接打开使用
- 5. 支持任意 OpenAI 兼容接口(输入端点 + 密钥即可)
+ 1. 点击「🔍 一键检测可用模型」自动获取模型列表(无需密钥)
+ 2. 如服务器代理可用,选择模型后直接对话
+ 3. 也可展开「🔧 自定义 API」输入自己的端点和密钥
+ 4. 铸渊自动切换 💬 对话 / 🔨 构建 / 📋 审查 / 🧠 大脑 模式
+ 5. 支持上传图片和文件(点击 📎 按钮或拖拽到对话区域)
⚠️ 危险操作
@@ -822,6 +847,25 @@ const KNOWN_ENDPOINTS = [
{label:'智谱 AI', base:'https://open.bigmodel.cn/api/paas/v4'},
];
+// ═══════════════════════════════════════════════════════
+// 内置模型目录(按网络区域分类)
+// 一键检测时,根据用户网络环境自动推荐可用模型
+// ═══════════════════════════════════════════════════════
+const MODEL_CATALOG = {
+ domestic: [
+ {provider:'yunwu', label:'云雾 AI(推荐·聚合)', models:['deepseek-chat','deepseek-reasoner','gpt-4o','claude-sonnet-4-20250514','gemini-2.5-pro-preview-05-06'], endpoint:'https://api.yunwu.ai/v1'},
+ {provider:'deepseek', label:'DeepSeek(国内直连)', models:['deepseek-chat','deepseek-reasoner'], endpoint:'https://api.deepseek.com/v1'},
+ {provider:'qwen', label:'通义千问 Qwen', models:['qwen-max','qwen-plus','qwen-turbo'], endpoint:'https://dashscope.aliyuncs.com/compatible-mode/v1'},
+ {provider:'moonshot', label:'Moonshot / Kimi', models:['moonshot-v1-8k','moonshot-v1-32k','moonshot-v1-128k'], endpoint:'https://api.moonshot.cn/v1'},
+ {provider:'zhipu', label:'智谱 AI', models:['glm-4','glm-4-flash'], endpoint:'https://open.bigmodel.cn/api/paas/v4'},
+ ],
+ international: [
+ {provider:'openai', label:'OpenAI', models:['gpt-4o','gpt-4-turbo','gpt-4o-mini'], endpoint:'https://api.openai.com/v1'},
+ {provider:'anthropic', label:'Anthropic', models:['claude-sonnet-4-20250514','claude-3-5-sonnet-20241022'], endpoint:'https://api.anthropic.com/v1'},
+ {provider:'google', label:'Google Gemini', models:['gemini-2.5-pro','gemini-2.0-flash'], endpoint:'https://generativelanguage.googleapis.com/v1beta/openai'},
+ ]
+};
+
const MODES = {
chat: {e:'💬',l:'对话模式', c:'var(--mc)'},
build: {e:'🔨',l:'构建模式', c:'var(--mb)'},
@@ -938,6 +982,29 @@ const HOLOLAKE_ENV = (function(){
})();
window.HOLOLAKE_ENV = HOLOLAKE_ENV;
+// ═══════════════════════════════════════════════════════
+// 服务器代理基址(staging/local → 调用生产服务器已配置的 API 密钥)
+// ═══════════════════════════════════════════════════════
+const SERVER_PROXY_BASE = HOLOLAKE_ENV === 'production' ? '' : 'https://guanghulab.com';
+
+// Patch proxy URLs for staging/local: point to production server
+if(HOLOLAKE_ENV !== 'production'){
+ GUEST_API.proxyUrl = SERVER_PROXY_BASE + '/api/chat';
+ TEAM_API.proxyUrl = SERVER_PROXY_BASE + '/api/chat';
+}
+
+// 检测用户网络环境(国内/国际)
+function detectNetworkRegion(){
+ var tz = '';
+ try{ tz = Intl.DateTimeFormat().resolvedOptions().timeZone || ''; }catch(e){}
+ var lang = (navigator.language || navigator.userLanguage || '').toLowerCase();
+ var chinaZones = ['Asia/Shanghai','Asia/Chongqing','Asia/Harbin','Asia/Urumqi','Asia/Hong_Kong','Asia/Macau','Asia/Taipei'];
+ if(chinaZones.some(function(z){ return tz.indexOf(z) >= 0; }) || lang.indexOf('zh') === 0){
+ return 'domestic';
+ }
+ return 'international';
+}
+
function ls(k){return localStorage.getItem(k)}
function lss(k,v){localStorage.setItem(k,v)}
@@ -1414,20 +1481,23 @@ function switchLoginMode(mode){
// ═══════════════════════════════════════════════════════
// AUTO-DETECT PROVIDER & MODELS
+// v4.0: 无密钥一键检测 + 网络环境自适应 + 服务器代理
+// 有密钥 → 原逻辑探测端点;无密钥 → 服务器代理 / 内置目录
// ═══════════════════════════════════════════════════════
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();
+ const key = keyEl ? keyEl.value.trim() : '';
+ // 无密钥 → 一键自动检测(服务器代理 / 内置目录)
if(!key){
- statusEl.innerHTML='
⚠️ 请先输入 API 密钥';
+ await autoDetectModels(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 = [];
if(userBase) candidates.push({label:userBase, base:userBase});
@@ -1455,11 +1525,9 @@ async function autoDetectAPI(ctx){
const mdls = (data.data||[]).map(function(m){return m.id;}).filter(Boolean).sort();
if(!mdls.length) continue;
- // Fill endpoint field with matched endpoint
const epEl = document.getElementById(ctx==='s'?'sep':'cep');
if(epEl) epEl.value = base;
- // Fill model dropdown with detected models
if(mdlSel){
mdlSel.innerHTML = mdls.map(function(m){return '
';}).join('');
mdlSel.disabled = false;
@@ -1477,12 +1545,106 @@ async function autoDetectAPI(ctx){
}
btnEl.disabled = false;
- btnEl.textContent = '🔍 检测模型';
+ btnEl.textContent = '🔍 自动检测';
+}
+
+// ═══════════════════════════════════════════════════════
+// 一键检测可用模型(无需 API 密钥)
+// 1. 检测网络环境(国内/国际)
+// 2. 尝试连接服务器代理获取实时模型列表
+// 3. 降级使用内置模型目录
+// ═══════════════════════════════════════════════════════
+async function autoDetectModels(ctx){
+ 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 epEl = document.getElementById(ctx==='s'?'sep':'cep');
+ const hintEl = document.getElementById(ctx==='s'?'sm-hint':'');
+
+ btnEl.disabled = true;
+ btnEl.textContent = '⏳ 检测中…';
+ statusEl.innerHTML = '
🌐 正在检测网络环境…';
+
+ const region = detectNetworkRegion();
+ const regionLabel = region === 'domestic' ? '🇨🇳 国内网络' : '🌍 国际网络';
+ statusEl.innerHTML = '
'+regionLabel+' · 正在获取可用模型…';
+
+ // 尝试连接服务器代理获取实时模型列表
+ let serverModels = null;
+ const proxyBase = SERVER_PROXY_BASE || location.origin;
+ try{
+ const ctrl = new AbortController();
+ const tid = setTimeout(function(){ctrl.abort();}, 5000);
+ const res = await fetch(proxyBase+'/api/models',{signal:ctrl.signal});
+ clearTimeout(tid);
+ if(res.ok){
+ const data = await res.json();
+ const list = data.data || data.models || [];
+ serverModels = list.map(function(m){return typeof m==='string'?m:m.id;}).filter(Boolean).sort();
+ }
+ }catch(e){console.debug('[AutoDetect] Server probe failed:',e.message);}
+
+ let source, totalCount = 0;
+
+ if(serverModels && serverModels.length > 0){
+ // 服务器代理可用 → 使用服务器模型列表
+ source = '服务器代理';
+ totalCount = serverModels.length;
+ if(mdlSel){
+ mdlSel.innerHTML = serverModels.map(function(m){return '
';}).join('');
+ mdlSel.disabled = false;
+ }
+ if(epEl) epEl.value = proxyBase + '/api/chat';
+ window._autoDetectServerProxy = true;
+ } else {
+ // 降级使用内置模型目录(按网络区域排序)
+ source = '内置模型库';
+ const primary = region === 'domestic' ? MODEL_CATALOG.domestic : MODEL_CATALOG.international;
+ const secondary = region === 'domestic' ? MODEL_CATALOG.international : MODEL_CATALOG.domestic;
+ const catalog = primary.concat(secondary);
+
+ if(mdlSel){
+ let html = '';
+ for(let i=0;i
';
+ for(let j=0;j'+p.models[j]+'';
+ totalCount++;
+ }
+ html += '';
+ }
+ mdlSel.innerHTML = html;
+ mdlSel.disabled = false;
+ // 自动选择第一个模型并设置对应端点
+ onModelSelectChange(ctx);
+ }
+ window._autoDetectServerProxy = false;
+ }
+
+ statusEl.innerHTML = '✅ 检测成功('+source+' · '+regionLabel+')· 发现 '+totalCount+' 个可用模型'
+ + (serverModels ? '
🔑 已连接服务器代理,无需输入 API 密钥' : '
⚠️ 服务器暂不可达,请输入对应提供商的 API 密钥后使用');
+
+ if(hintEl) hintEl.textContent = serverModels ? '已连接服务器代理,选择模型后可直接开始对话' : '选择模型后,请输入对应提供商的 API 密钥';
+
+ btnEl.disabled = false;
+ btnEl.textContent = '🔍 自动检测';
+}
+
+// 模型选择变更 → 自动切换端点
+function onModelSelectChange(ctx){
+ const mdlSel = document.getElementById(ctx==='s'?'sm':'cm');
+ const epEl = document.getElementById(ctx==='s'?'sep':'cep');
+ if(!mdlSel || !epEl) return;
+ const opt = mdlSel.options[mdlSel.selectedIndex];
+ if(!opt) return;
+ const ep = opt.getAttribute('data-endpoint');
+ if(ep) epEl.value = ep;
}
function doSetup(){
const un = document.getElementById('suid').value;
- const k = document.getElementById('sk').value.trim();
+ 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');
@@ -1491,14 +1653,35 @@ function doSetup(){
alert('请选择你的开发者身份');
return;
}
- if(!k){errEl.style.display='block';return;}
- errEl.style.display='none';
- if(!base){
- alert('请输入 API 端点 URL');
+ if(!md){
+ alert('请先点击「🔍 自动检测」检测可用模型,然后选择一个模型');
return;
}
- if(!md){
- alert('请先点击「🔍 检测模型」检测可用模型,然后选择一个模型');
+
+ // 服务器代理模式(一键检测,无需密钥)
+ if(window._autoDetectServerProxy && !k){
+ A.demo = true;
+ A.teamMode = true;
+ A.key = '';
+ A.prov = 'custom';
+ A.mdl = md;
+ A.base = base;
+ lss('zy_teammode','1');
+ lss('zy_base',base); lss('zy_mdl',md); lss('zy_prov','proxy');
+ setIdentity(un, '');
+ showApp();
+ return;
+ }
+
+ // 自定义 API 模式(需要密钥)
+ if(!k){
+ if(errEl) errEl.style.display='block';
+ alert('请输入 API 密钥,或点击「🔍 自动检测」使用服务器代理');
+ return;
+ }
+ if(errEl) errEl.style.display='none';
+ if(!base){
+ alert('请输入 API 端点 URL');
return;
}