mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-06 08:06:43 +08:00
feat(settings): persist LLM base URL presets
This commit is contained in:
@@ -17,11 +17,13 @@ export interface LlmProviderAuthStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LlmProviderUrlPreset {
|
export interface LlmProviderUrlPreset {
|
||||||
|
id: string
|
||||||
label: string
|
label: string
|
||||||
value: string
|
value: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LlmProviderUrlPresetItem {
|
export interface LlmProviderUrlPresetItem {
|
||||||
|
id: string
|
||||||
title: string
|
title: string
|
||||||
value: string
|
value: string
|
||||||
subtitle?: string
|
subtitle?: string
|
||||||
@@ -80,6 +82,7 @@ interface UseLlmProviderDirectoryOptions {
|
|||||||
provider: Ref<string>
|
provider: Ref<string>
|
||||||
apiKey: Ref<string>
|
apiKey: Ref<string>
|
||||||
baseUrl: Ref<string>
|
baseUrl: Ref<string>
|
||||||
|
baseUrlPreset?: Ref<string>
|
||||||
model: Ref<string>
|
model: Ref<string>
|
||||||
maxContextTokens?: Ref<number>
|
maxContextTokens?: Ref<number>
|
||||||
authConnected?: Ref<boolean>
|
authConnected?: Ref<boolean>
|
||||||
@@ -110,6 +113,7 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions)
|
|||||||
const providerItems = computed(() => providers.value.map(item => ({ title: item.name, value: item.id })))
|
const providerItems = computed(() => providers.value.map(item => ({ title: item.name, value: item.id })))
|
||||||
const baseUrlPresetItems = computed<LlmProviderUrlPresetItem[]>(() =>
|
const baseUrlPresetItems = computed<LlmProviderUrlPresetItem[]>(() =>
|
||||||
(selectedProvider.value?.base_url_presets || []).map(item => ({
|
(selectedProvider.value?.base_url_presets || []).map(item => ({
|
||||||
|
id: item.id,
|
||||||
title: item.value,
|
title: item.value,
|
||||||
value: item.value,
|
value: item.value,
|
||||||
subtitle: item.label,
|
subtitle: item.label,
|
||||||
@@ -150,14 +154,37 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions)
|
|||||||
|
|
||||||
const currentBaseUrl = normalizeValue(options.baseUrl.value)
|
const currentBaseUrl = normalizeValue(options.baseUrl.value)
|
||||||
const defaultBaseUrl = provider.default_base_url || ''
|
const defaultBaseUrl = provider.default_base_url || ''
|
||||||
|
const defaultPresetId = normalizeValue(provider.base_url_presets?.[0]?.id)
|
||||||
if (reset) {
|
if (reset) {
|
||||||
options.baseUrl.value = defaultBaseUrl
|
options.baseUrl.value = defaultBaseUrl
|
||||||
|
if (options.baseUrlPreset) {
|
||||||
|
options.baseUrlPreset.value = defaultPresetId
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!currentBaseUrl && defaultBaseUrl) {
|
if (!currentBaseUrl && defaultBaseUrl) {
|
||||||
options.baseUrl.value = defaultBaseUrl
|
options.baseUrl.value = defaultBaseUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!options.baseUrlPreset) return
|
||||||
|
|
||||||
|
const currentPresetId = normalizeValue(options.baseUrlPreset.value)
|
||||||
|
if (currentPresetId) return
|
||||||
|
|
||||||
|
const matchedPreset = (provider.base_url_presets || []).find(
|
||||||
|
item => normalizeValue(item.value) === normalizeValue(options.baseUrl.value),
|
||||||
|
)
|
||||||
|
options.baseUrlPreset.value = matchedPreset?.id || defaultPresetId
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBaseUrlPreset(presetId?: string, presetValue?: string) {
|
||||||
|
if (!options.baseUrlPreset) return
|
||||||
|
|
||||||
|
options.baseUrlPreset.value = normalizeValue(presetId)
|
||||||
|
if (presetValue !== undefined) {
|
||||||
|
options.baseUrl.value = presetValue || ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleProviderSelection(resetBaseUrl = true) {
|
function handleProviderSelection(resetBaseUrl = true) {
|
||||||
@@ -225,6 +252,7 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions)
|
|||||||
provider: normalizeValue(options.provider.value),
|
provider: normalizeValue(options.provider.value),
|
||||||
api_key: normalizeValue(options.apiKey.value) || undefined,
|
api_key: normalizeValue(options.apiKey.value) || undefined,
|
||||||
base_url: normalizeValue(options.baseUrl.value) || undefined,
|
base_url: normalizeValue(options.baseUrl.value) || undefined,
|
||||||
|
base_url_preset: normalizeValue(options.baseUrlPreset?.value) || undefined,
|
||||||
force_refresh: forceRefresh,
|
force_refresh: forceRefresh,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -363,6 +391,7 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions)
|
|||||||
showApiKeyField,
|
showApiKeyField,
|
||||||
hasUsableCredential,
|
hasUsableCredential,
|
||||||
canRefreshModels,
|
canRefreshModels,
|
||||||
|
setBaseUrlPreset,
|
||||||
authDialogVisible,
|
authDialogVisible,
|
||||||
authPolling,
|
authPolling,
|
||||||
authPopupBlocked,
|
authPopupBlocked,
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ export interface WizardData {
|
|||||||
supportAudioInputOutput: boolean
|
supportAudioInputOutput: boolean
|
||||||
apiKey: string
|
apiKey: string
|
||||||
baseUrl: string
|
baseUrl: string
|
||||||
|
baseUrlPreset: string
|
||||||
maxContextTokens: number
|
maxContextTokens: number
|
||||||
voiceApiKey: string
|
voiceApiKey: string
|
||||||
voiceBaseUrl: string
|
voiceBaseUrl: string
|
||||||
@@ -240,6 +241,7 @@ const wizardData = ref<WizardData>({
|
|||||||
supportAudioInputOutput: false,
|
supportAudioInputOutput: false,
|
||||||
apiKey: '',
|
apiKey: '',
|
||||||
baseUrl: 'https://api.deepseek.com',
|
baseUrl: 'https://api.deepseek.com',
|
||||||
|
baseUrlPreset: '',
|
||||||
maxContextTokens: 64,
|
maxContextTokens: 64,
|
||||||
voiceApiKey: '',
|
voiceApiKey: '',
|
||||||
voiceBaseUrl: '',
|
voiceBaseUrl: '',
|
||||||
@@ -1396,6 +1398,7 @@ export function useSetupWizard() {
|
|||||||
LLM_SUPPORT_AUDIO_INPUT_OUTPUT: wizardData.value.agent.supportAudioInputOutput,
|
LLM_SUPPORT_AUDIO_INPUT_OUTPUT: wizardData.value.agent.supportAudioInputOutput,
|
||||||
LLM_API_KEY: wizardData.value.agent.apiKey,
|
LLM_API_KEY: wizardData.value.agent.apiKey,
|
||||||
LLM_BASE_URL: wizardData.value.agent.baseUrl || null,
|
LLM_BASE_URL: wizardData.value.agent.baseUrl || null,
|
||||||
|
LLM_BASE_URL_PRESET: wizardData.value.agent.baseUrlPreset || null,
|
||||||
LLM_MAX_CONTEXT_TOKENS: wizardData.value.agent.maxContextTokens,
|
LLM_MAX_CONTEXT_TOKENS: wizardData.value.agent.maxContextTokens,
|
||||||
AI_VOICE_API_KEY: wizardData.value.agent.voiceApiKey || null,
|
AI_VOICE_API_KEY: wizardData.value.agent.voiceApiKey || null,
|
||||||
AI_VOICE_BASE_URL: wizardData.value.agent.voiceBaseUrl || null,
|
AI_VOICE_BASE_URL: wizardData.value.agent.voiceBaseUrl || null,
|
||||||
@@ -1503,6 +1506,7 @@ export function useSetupWizard() {
|
|||||||
wizardData.value.agent.supportAudioInputOutput = Boolean(result.data.LLM_SUPPORT_AUDIO_INPUT_OUTPUT)
|
wizardData.value.agent.supportAudioInputOutput = Boolean(result.data.LLM_SUPPORT_AUDIO_INPUT_OUTPUT)
|
||||||
wizardData.value.agent.apiKey = result.data.LLM_API_KEY || ''
|
wizardData.value.agent.apiKey = result.data.LLM_API_KEY || ''
|
||||||
wizardData.value.agent.baseUrl = result.data.LLM_BASE_URL || ''
|
wizardData.value.agent.baseUrl = result.data.LLM_BASE_URL || ''
|
||||||
|
wizardData.value.agent.baseUrlPreset = result.data.LLM_BASE_URL_PRESET || ''
|
||||||
wizardData.value.agent.maxContextTokens = result.data.LLM_MAX_CONTEXT_TOKENS || 64
|
wizardData.value.agent.maxContextTokens = result.data.LLM_MAX_CONTEXT_TOKENS || 64
|
||||||
wizardData.value.agent.voiceApiKey = result.data.AI_VOICE_API_KEY || ''
|
wizardData.value.agent.voiceApiKey = result.data.AI_VOICE_API_KEY || ''
|
||||||
wizardData.value.agent.voiceBaseUrl = result.data.AI_VOICE_BASE_URL || ''
|
wizardData.value.agent.voiceBaseUrl = result.data.AI_VOICE_BASE_URL || ''
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ const SystemSettings = ref<any>({
|
|||||||
LLM_SUPPORT_AUDIO_INPUT_OUTPUT: false,
|
LLM_SUPPORT_AUDIO_INPUT_OUTPUT: false,
|
||||||
LLM_API_KEY: null,
|
LLM_API_KEY: null,
|
||||||
LLM_BASE_URL: 'https://api.deepseek.com',
|
LLM_BASE_URL: 'https://api.deepseek.com',
|
||||||
|
LLM_BASE_URL_PRESET: null,
|
||||||
AI_VOICE_API_KEY: null,
|
AI_VOICE_API_KEY: null,
|
||||||
AI_VOICE_BASE_URL: null,
|
AI_VOICE_BASE_URL: null,
|
||||||
AI_VOICE_STT_MODEL: 'gpt-4o-mini-transcribe',
|
AI_VOICE_STT_MODEL: 'gpt-4o-mini-transcribe',
|
||||||
@@ -179,6 +180,7 @@ type LlmSettingsSnapshot = {
|
|||||||
LLM_THINKING_LEVEL: string
|
LLM_THINKING_LEVEL: string
|
||||||
LLM_API_KEY: string
|
LLM_API_KEY: string
|
||||||
LLM_BASE_URL: string
|
LLM_BASE_URL: string
|
||||||
|
LLM_BASE_URL_PRESET: string
|
||||||
}
|
}
|
||||||
|
|
||||||
let llmTestRequestId = 0
|
let llmTestRequestId = 0
|
||||||
@@ -205,6 +207,13 @@ const llmBaseUrlRef = computed({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const llmBaseUrlPresetRef = computed({
|
||||||
|
get: () => String(SystemSettings.value.Basic.LLM_BASE_URL_PRESET ?? ''),
|
||||||
|
set: value => {
|
||||||
|
SystemSettings.value.Basic.LLM_BASE_URL_PRESET = value || ''
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const llmModelRef = computed({
|
const llmModelRef = computed({
|
||||||
get: () => String(SystemSettings.value.Basic.LLM_MODEL ?? ''),
|
get: () => String(SystemSettings.value.Basic.LLM_MODEL ?? ''),
|
||||||
set: value => {
|
set: value => {
|
||||||
@@ -231,6 +240,7 @@ const {
|
|||||||
showBaseUrlField,
|
showBaseUrlField,
|
||||||
showApiKeyField,
|
showApiKeyField,
|
||||||
canRefreshModels,
|
canRefreshModels,
|
||||||
|
setBaseUrlPreset,
|
||||||
authDialogVisible,
|
authDialogVisible,
|
||||||
authPolling,
|
authPolling,
|
||||||
authPopupBlocked,
|
authPopupBlocked,
|
||||||
@@ -248,6 +258,7 @@ const {
|
|||||||
provider: llmProviderRef,
|
provider: llmProviderRef,
|
||||||
apiKey: llmApiKeyRef,
|
apiKey: llmApiKeyRef,
|
||||||
baseUrl: llmBaseUrlRef,
|
baseUrl: llmBaseUrlRef,
|
||||||
|
baseUrlPreset: llmBaseUrlPresetRef,
|
||||||
model: llmModelRef,
|
model: llmModelRef,
|
||||||
maxContextTokens: llmMaxContextRef,
|
maxContextTokens: llmMaxContextRef,
|
||||||
})
|
})
|
||||||
@@ -260,6 +271,7 @@ function buildLlmSnapshot(): LlmSettingsSnapshot {
|
|||||||
LLM_THINKING_LEVEL: String(SystemSettings.value.Basic.LLM_THINKING_LEVEL ?? 'off'),
|
LLM_THINKING_LEVEL: String(SystemSettings.value.Basic.LLM_THINKING_LEVEL ?? 'off'),
|
||||||
LLM_API_KEY: String(SystemSettings.value.Basic.LLM_API_KEY ?? ''),
|
LLM_API_KEY: String(SystemSettings.value.Basic.LLM_API_KEY ?? ''),
|
||||||
LLM_BASE_URL: String(SystemSettings.value.Basic.LLM_BASE_URL ?? ''),
|
LLM_BASE_URL: String(SystemSettings.value.Basic.LLM_BASE_URL ?? ''),
|
||||||
|
LLM_BASE_URL_PRESET: String(SystemSettings.value.Basic.LLM_BASE_URL_PRESET ?? ''),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,6 +287,7 @@ function buildLlmTestPayload(snapshot: LlmSettingsSnapshot) {
|
|||||||
thinking_level: snapshot.LLM_THINKING_LEVEL.trim(),
|
thinking_level: snapshot.LLM_THINKING_LEVEL.trim(),
|
||||||
api_key: snapshot.LLM_API_KEY.trim(),
|
api_key: snapshot.LLM_API_KEY.trim(),
|
||||||
base_url: snapshot.LLM_BASE_URL.trim(),
|
base_url: snapshot.LLM_BASE_URL.trim(),
|
||||||
|
base_url_preset: snapshot.LLM_BASE_URL_PRESET.trim(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1016,7 +1029,11 @@ watch(currentLlmSnapshotKey, (snapshotKey, previousSnapshotKey) => {
|
|||||||
<VCombobox
|
<VCombobox
|
||||||
:model-value="SystemSettings.Basic.LLM_BASE_URL"
|
:model-value="SystemSettings.Basic.LLM_BASE_URL"
|
||||||
@update:model-value="(value: any) => {
|
@update:model-value="(value: any) => {
|
||||||
SystemSettings.Basic.LLM_BASE_URL = typeof value === 'object' && value !== null ? value.value : (value || '');
|
if (typeof value === 'object' && value !== null) {
|
||||||
|
setBaseUrlPreset(value.id, value.value);
|
||||||
|
} else {
|
||||||
|
setBaseUrlPreset('', value || '');
|
||||||
|
}
|
||||||
}"
|
}"
|
||||||
:label="t('setting.system.llmBaseUrl')"
|
:label="t('setting.system.llmBaseUrl')"
|
||||||
:hint="t('setting.system.llmBaseUrlHint')"
|
:hint="t('setting.system.llmBaseUrlHint')"
|
||||||
|
|||||||
@@ -30,6 +30,13 @@ const baseUrlRef = computed({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const baseUrlPresetRef = computed({
|
||||||
|
get: () => wizardData.value.agent.baseUrlPreset,
|
||||||
|
set: value => {
|
||||||
|
wizardData.value.agent.baseUrlPreset = value || ''
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const modelRef = computed({
|
const modelRef = computed({
|
||||||
get: () => wizardData.value.agent.model,
|
get: () => wizardData.value.agent.model,
|
||||||
set: value => {
|
set: value => {
|
||||||
@@ -63,6 +70,7 @@ const {
|
|||||||
showBaseUrlField,
|
showBaseUrlField,
|
||||||
showApiKeyField,
|
showApiKeyField,
|
||||||
canRefreshModels,
|
canRefreshModels,
|
||||||
|
setBaseUrlPreset,
|
||||||
authDialogVisible,
|
authDialogVisible,
|
||||||
authPolling,
|
authPolling,
|
||||||
authPopupBlocked,
|
authPopupBlocked,
|
||||||
@@ -80,6 +88,7 @@ const {
|
|||||||
provider: providerRef,
|
provider: providerRef,
|
||||||
apiKey: apiKeyRef,
|
apiKey: apiKeyRef,
|
||||||
baseUrl: baseUrlRef,
|
baseUrl: baseUrlRef,
|
||||||
|
baseUrlPreset: baseUrlPresetRef,
|
||||||
model: modelRef,
|
model: modelRef,
|
||||||
maxContextTokens: maxContextTokensRef,
|
maxContextTokens: maxContextTokensRef,
|
||||||
authConnected: authConnectedRef,
|
authConnected: authConnectedRef,
|
||||||
@@ -232,7 +241,11 @@ onMounted(async () => {
|
|||||||
<VCombobox
|
<VCombobox
|
||||||
:model-value="wizardData.agent.baseUrl"
|
:model-value="wizardData.agent.baseUrl"
|
||||||
@update:model-value="(value: any) => {
|
@update:model-value="(value: any) => {
|
||||||
wizardData.agent.baseUrl = typeof value === 'object' && value !== null ? value.value : (value || '');
|
if (typeof value === 'object' && value !== null) {
|
||||||
|
setBaseUrlPreset(value.id, value.value);
|
||||||
|
} else {
|
||||||
|
setBaseUrlPreset('', value || '');
|
||||||
|
}
|
||||||
}"
|
}"
|
||||||
:label="t('setting.system.llmBaseUrl')"
|
:label="t('setting.system.llmBaseUrl')"
|
||||||
:hint="t('setting.system.llmBaseUrlHint')"
|
:hint="t('setting.system.llmBaseUrlHint')"
|
||||||
|
|||||||
Reference in New Issue
Block a user