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