This commit is contained in:
2026-06-09 13:01:01 +08:00
parent 4dcf8c351a
commit 4429efdc7c
2 changed files with 351 additions and 48 deletions
+69 -2
View File
@@ -144,6 +144,15 @@
padding: 3px 10px;
border-radius: 20px;
}
header .model-select {
max-width: 260px;
cursor: pointer;
outline: none;
}
header .model-select:disabled {
opacity: .65;
cursor: not-allowed;
}
.header-actions {
display: flex;
align-items: center;
@@ -466,7 +475,9 @@
{{ .Title }}
</div>
<div class="header-actions">
<span class="model-badge">{{ .Model }}</span>
<select id="modelSelect" class="model-badge model-select" title="切换 OpenAI 配置">
<option value="{{ .OpenAIName }}">{{ .Model }}</option>
</select>
<button id="btnSearch" title="开启后,本轮提问会先联网搜索">联网搜索:关</button>
<button id="btnPreset" title="设置预先提示词">预设</button>
<button id="btnClear" title="开始新对话">新对话</button>
@@ -531,6 +542,8 @@ let history = []; // {role, content, image_url?}
let currentConvId = null;
let pending = false;
let webSearchEnabled = false;
let openAIProfiles = [];
let activeOpenAIName = '{{ .OpenAIName }}';
let imageB64 = ''; // 当前待发送图片的 data URI
let imageName = '';
@@ -542,6 +555,7 @@ const btnSend = document.getElementById('btnSend');
const btnClear = document.getElementById('btnClear');
const btnPreset = document.getElementById('btnPreset');
const btnSearch = document.getElementById('btnSearch');
const modelSelect = document.getElementById('modelSelect');
const btnNewChat = document.getElementById('btnNewChat');
const convList = document.getElementById('convList');
const presetModal = document.getElementById('presetModal');
@@ -615,6 +629,7 @@ function setInputDisabled(disabled) {
inputBox.disabled = disabled;
fileInput.disabled = disabled;
btnSearch.disabled = disabled;
modelSelect.disabled = disabled || openAIProfiles.length <= 1;
}
function updateSearchButton() {
@@ -622,6 +637,27 @@ function updateSearchButton() {
btnSearch.textContent = webSearchEnabled ? '联网搜索:开' : '联网搜索:关';
}
async function loadOpenAIProfiles() {
const res = await fetch('/api/openai');
if (!res.ok) {
const err = await res.json().catch(() => ({ error: '加载模型配置失败' }));
throw new Error(err.error || '加载模型配置失败');
}
const data = await res.json();
openAIProfiles = Array.isArray(data.profiles) ? data.profiles : [];
activeOpenAIName = data.active || activeOpenAIName;
modelSelect.innerHTML = '';
for (const profile of openAIProfiles) {
const opt = document.createElement('option');
opt.value = profile.name;
opt.textContent = `${profile.name} · ${profile.model}`;
opt.selected = profile.name === activeOpenAIName;
modelSelect.appendChild(opt);
}
modelSelect.disabled = pending || openAIProfiles.length <= 1;
}
// ── 对话列表 ──────────────────────────────────────────────
async function loadConversationList() {
try {
@@ -784,7 +820,12 @@ async function streamChat(messages, aiBubble, webSearch = false) {
const res = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ conversation_id: currentConvId, messages, web_search: webSearch }),
body: JSON.stringify({
conversation_id: currentConvId,
messages,
web_search: webSearch,
openai_name: activeOpenAIName,
}),
});
if (!res.ok) {
@@ -997,6 +1038,31 @@ btnSearch.addEventListener('click', () => {
webSearchEnabled = !webSearchEnabled;
updateSearchButton();
});
modelSelect.addEventListener('change', async () => {
if (pending) {
modelSelect.value = activeOpenAIName;
return;
}
const nextName = modelSelect.value;
const prevName = activeOpenAIName;
try {
const res = await fetch('/api/openai/active', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: nextName }),
});
if (!res.ok) {
const err = await res.json().catch(() => ({ error: '切换模型失败' }));
throw new Error(err.error || '切换模型失败');
}
const data = await res.json();
activeOpenAIName = data.active;
modelSelect.value = activeOpenAIName;
} catch (e) {
modelSelect.value = prevName;
alert(e.message);
}
});
btnNewChat.addEventListener('click', newConversation);
btnClear.addEventListener('click', newConversation);
btnPreset.addEventListener('click', openPresetModal);
@@ -1016,6 +1082,7 @@ presetModal.addEventListener('click', e => {
// 自动聚焦 & 初始化
updateSearchButton();
loadOpenAIProfiles().catch(e => alert(e.message));
loadConversationList();
inputBox.focus();
</script>