fix(ena-planner): align channel options and model-fetch behavior with story-summary
This commit is contained in:
@@ -103,9 +103,6 @@
|
|||||||
<option value="openai">OpenAI compatible</option>
|
<option value="openai">OpenAI compatible</option>
|
||||||
<option value="gemini">Gemini compatible</option>
|
<option value="gemini">Gemini compatible</option>
|
||||||
<option value="claude">Claude compatible</option>
|
<option value="claude">Claude compatible</option>
|
||||||
<option value="deepseek">DeepSeek compatible</option>
|
|
||||||
<option value="cohere">Cohere compatible</option>
|
|
||||||
<option value="custom">Custom compatible</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group hidden" id="ep_model_row">
|
<div class="form-group hidden" id="ep_model_row">
|
||||||
@@ -123,7 +120,6 @@
|
|||||||
<input id="ep_api_key" type="password" class="input" placeholder="仅本地保存,不上传">
|
<input id="ep_api_key" type="password" class="input" placeholder="仅本地保存,不上传">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-hint">不需要填写 /v1 前缀,后端会按渠道自动处理。</div>
|
|
||||||
<div id="ep_model_selector" class="hidden" style="margin-top:12px;">
|
<div id="ep_model_selector" class="hidden" style="margin-top:12px;">
|
||||||
<label class="form-label">选择模型</label>
|
<label class="form-label">选择模型</label>
|
||||||
<select id="ep_model_select" class="input">
|
<select id="ep_model_select" class="input">
|
||||||
|
|||||||
@@ -890,9 +890,6 @@ async function callPlanner(messages, options = {}) {
|
|||||||
claude: chat_completion_sources.CLAUDE,
|
claude: chat_completion_sources.CLAUDE,
|
||||||
gemini: chat_completion_sources.MAKERSUITE,
|
gemini: chat_completion_sources.MAKERSUITE,
|
||||||
google: chat_completion_sources.MAKERSUITE,
|
google: chat_completion_sources.MAKERSUITE,
|
||||||
cohere: chat_completion_sources.COHERE,
|
|
||||||
deepseek: chat_completion_sources.DEEPSEEK,
|
|
||||||
custom: chat_completion_sources.CUSTOM,
|
|
||||||
}[channel];
|
}[channel];
|
||||||
if (!source) throw new Error(`Unsupported channel: ${channel}`);
|
if (!source) throw new Error(`Unsupported channel: ${channel}`);
|
||||||
|
|
||||||
@@ -1029,58 +1026,62 @@ async function callPlanner(messages, options = {}) {
|
|||||||
async function fetchModelsForUi() {
|
async function fetchModelsForUi() {
|
||||||
const s = ensureSettings();
|
const s = ensureSettings();
|
||||||
const channel = String(s.api?.channel || 'st_main').toLowerCase();
|
const channel = String(s.api?.channel || 'st_main').toLowerCase();
|
||||||
const source = channel === 'st_main'
|
if (channel === 'st_main') {
|
||||||
? String(oai_settings?.chat_completion_source || chat_completion_sources.OPENAI)
|
const source = String(oai_settings?.chat_completion_source || chat_completion_sources.OPENAI);
|
||||||
: ({
|
const payload = {
|
||||||
openai: chat_completion_sources.OPENAI,
|
chat_completion_source: source,
|
||||||
claude: chat_completion_sources.CLAUDE,
|
reverse_proxy: oai_settings?.reverse_proxy,
|
||||||
gemini: chat_completion_sources.MAKERSUITE,
|
proxy_password: oai_settings?.proxy_password,
|
||||||
google: chat_completion_sources.MAKERSUITE,
|
};
|
||||||
cohere: chat_completion_sources.COHERE,
|
const res = await fetch('/api/backends/chat-completions/status', {
|
||||||
deepseek: chat_completion_sources.DEEPSEEK,
|
method: 'POST',
|
||||||
custom: chat_completion_sources.CUSTOM,
|
headers: {
|
||||||
}[channel]);
|
...getRequestHeaders(),
|
||||||
if (!source) throw new Error(`Unsupported channel: ${channel}`);
|
'Content-Type': 'application/json'
|
||||||
const providerUrl = normalizeProxyBaseUrl(s.api?.url);
|
},
|
||||||
const providerKey = String(s.api?.key || '').trim();
|
body: JSON.stringify(payload),
|
||||||
if (channel !== 'st_main') {
|
cache: 'no-cache',
|
||||||
if (!providerUrl) throw new Error('Please provide API URL');
|
});
|
||||||
if (!providerKey) throw new Error('Please provide API KEY');
|
if (!res.ok) {
|
||||||
|
const text = await res.text().catch(() => '');
|
||||||
|
throw new Error(`Model list request failed: ${res.status} ${text}`.slice(0, 300));
|
||||||
|
}
|
||||||
|
const data = await res.json();
|
||||||
|
const list = Array.isArray(data?.data) ? data.data : [];
|
||||||
|
return list.map(x => x?.id).filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
const payload = {
|
// Keep consistent with story-summary: direct URL probing for non-ST channels.
|
||||||
chat_completion_source: source,
|
let baseUrl = String(s.api?.url || '').trim().replace(/\/+$/, '');
|
||||||
reverse_proxy: channel === 'st_main' ? oai_settings?.reverse_proxy : providerUrl,
|
const apiKey = String(s.api?.key || '').trim();
|
||||||
proxy_password: channel === 'st_main' ? oai_settings?.proxy_password : providerKey,
|
if (!baseUrl) throw new Error('请先填写 API URL');
|
||||||
|
if (!apiKey) throw new Error('请先填写 API KEY');
|
||||||
|
|
||||||
|
const tryFetch = async (url) => {
|
||||||
|
try {
|
||||||
|
const res = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}`, Accept: 'application/json' } });
|
||||||
|
if (!res.ok) return null;
|
||||||
|
const data = await res.json();
|
||||||
|
if (!data) return null;
|
||||||
|
if (Array.isArray(data?.data)) return data.data.map(x => x?.id).filter(Boolean);
|
||||||
|
if (Array.isArray(data?.models)) return data.models.map(x => x?.id || x?.name).filter(Boolean);
|
||||||
|
} catch { }
|
||||||
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (source === chat_completion_sources.CUSTOM) {
|
if (baseUrl.endsWith('/v1')) baseUrl = baseUrl.slice(0, -3);
|
||||||
payload.custom_url = oai_settings?.custom_url;
|
if (baseUrl.endsWith('/v1beta')) baseUrl = baseUrl.slice(0, -7);
|
||||||
payload.custom_include_headers = oai_settings?.custom_include_headers;
|
|
||||||
|
const candidates = channel === 'gemini' || channel === 'google'
|
||||||
|
? [`${baseUrl}/v1beta/models`, `${baseUrl}/v1/models`, `${baseUrl}/models`]
|
||||||
|
: [`${baseUrl}/v1/models`, `${baseUrl}/models`];
|
||||||
|
|
||||||
|
for (const url of candidates) {
|
||||||
|
const models = await tryFetch(url);
|
||||||
|
if (models?.length) return [...new Set(models)];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source === chat_completion_sources.AZURE_OPENAI) {
|
throw new Error('未获取到模型');
|
||||||
payload.azure_base_url = oai_settings?.azure_base_url;
|
|
||||||
payload.azure_deployment_name = oai_settings?.azure_deployment_name;
|
|
||||||
payload.azure_api_version = oai_settings?.azure_api_version;
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await fetch('/api/backends/chat-completions/status', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
...getRequestHeaders(),
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify(payload),
|
|
||||||
cache: 'no-cache',
|
|
||||||
});
|
|
||||||
if (!res.ok) {
|
|
||||||
const text = await res.text().catch(() => '');
|
|
||||||
throw new Error(`Model list request failed: ${res.status} ${text}`.slice(0, 300));
|
|
||||||
}
|
|
||||||
const data = await res.json();
|
|
||||||
const list = Array.isArray(data?.data) ? data.data : [];
|
|
||||||
return list.map(x => x?.id).filter(Boolean);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function debugWorldbookForUi() {
|
async function debugWorldbookForUi() {
|
||||||
@@ -1528,4 +1529,3 @@ export function cleanupEnaPlanner() {
|
|||||||
}
|
}
|
||||||
delete window.xiaobaixEnaPlanner;
|
delete window.xiaobaixEnaPlanner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user