-
+
+
+
+
留空则不修改现有 Key。
+
+
-
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
+
+
+ 高级参数
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/ui/api-config-bindings.js b/ui/api-config-bindings.js
index 018c3ee..fc44385 100644
--- a/ui/api-config-bindings.js
+++ b/ui/api-config-bindings.js
@@ -38,6 +38,17 @@ export function bindApiConfigPanel(container) {
_switchParamSections($c, $(this).val());
});
+ // 弹窗:接口类型切换(Google 自动填 URL)
+ $c.find('#amily2_pf_provider').on('change', function () {
+ _handleProviderChange($c, $(this).val());
+ });
+
+ // 弹窗:获取模型列表
+ $c.find('#amily2_pf_fetch_models').on('click', () => _fetchModels($c));
+
+ // 弹窗:测试连接
+ $c.find('#amily2_pf_test_conn').on('click', () => _testConnection($c));
+
// 弹窗:关闭
$c.find('#amily2_profile_modal_close, #amily2_profile_modal_cancel').on('click', () => closeModal($c));
$c.find('#amily2_profile_modal').on('click', function (e) {
@@ -246,12 +257,14 @@ async function openModal($c, id) {
$c.find('#amily2_pf_return_documents').prop('checked', p.returnDocuments);
}
_switchParamSections($c, p.type);
+ _handleProviderChange($c, p.provider);
} else {
// 新建模式
$c.find('#amily2_profile_modal_title').html('
新建连接配置');
$c.find('#amily2_pf_type').val('chat').prop('disabled', false);
$c.find('#amily2_pf_name, #amily2_pf_url, #amily2_pf_key, #amily2_pf_model').val('');
$c.find('#amily2_pf_provider').val('openai');
+ _handleProviderChange($c, 'openai');
$c.find('#amily2_pf_max_tokens').val(65500);
$c.find('#amily2_pf_temperature').val(1.0);
$c.find('#amily2_pf_dimensions').val('');
@@ -261,6 +274,10 @@ async function openModal($c, id) {
_switchParamSections($c, 'chat');
}
+ // 清空上次测试结果和模型列表缓存
+ $c.find('#amily2_pf_test_result').text('');
+ $c.find('#amily2_pf_model_list').empty();
+
$modal.css('display', 'flex');
}
@@ -322,6 +339,188 @@ async function saveProfile($c) {
}
}
+// ── 获取模型 / 测试连接 ───────────────────────────────────────────────────────
+
+async function _fetchModels($c) {
+ const apiUrl = $c.find('#amily2_pf_url').val().trim();
+ const apiKey = $c.find('#amily2_pf_key').val().trim();
+ const provider = $c.find('#amily2_pf_provider').val();
+
+ if (!apiUrl) { toastr.warning('请先填写 API 地址。'); return; }
+
+ const $btn = $c.find('#amily2_pf_fetch_models').prop('disabled', true);
+ $btn.html('
获取中...');
+
+ try {
+ let models;
+
+ if (provider === 'google') {
+ // Google 用原生 API,以 ?key= 传参,返回 models[] 而非 data[]
+ if (!apiKey) { toastr.warning('请先填写 Google API Key。'); return; }
+ const resp = await fetch(
+ `https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(apiKey)}`
+ );
+ if (!resp.ok) {
+ const status = resp.status;
+ toastr.error(status === 400 ? '获取失败:API Key 格式错误。'
+ : status === 403 ? '获取失败:API Key 无效或无权限。'
+ : `获取失败:HTTP ${status}`);
+ return;
+ }
+ const data = await resp.json();
+ // 只保留支持文本生成的模型
+ models = (data.models ?? [])
+ .filter(m => m.supportedGenerationMethods?.some(
+ method => ['generateContent', 'embedContent'].includes(method)
+ ))
+ .map(m => m.name.replace(/^models\//, ''));
+ } else {
+ // OpenAI 兼容接口
+ const baseUrl = apiUrl.replace(/\/+$/, '');
+ const headers = {};
+ if (apiKey) headers['Authorization'] = `Bearer ${apiKey}`;
+
+ const resp = await fetch(`${baseUrl}/models`, { headers });
+ if (!resp.ok) {
+ const status = resp.status;
+ if (status === 401 || status === 403) {
+ toastr.error('获取失败:API Key 无效或无权限。');
+ } else if (status === 404) {
+ toastr.warning('该接口不支持模型列表查询,请手动填写模型 ID。');
+ } else {
+ toastr.error(`获取失败:HTTP ${status}`);
+ }
+ return;
+ }
+ const data = await resp.json();
+ models = (data.data ?? []).map(m => m.id).filter(Boolean);
+ }
+
+ if (models.length === 0) {
+ toastr.warning('未获取到模型列表,请手动填写。');
+ return;
+ }
+
+ const $dl = $c.find('#amily2_pf_model_list');
+ $dl.html(models.map(m => `