chore: enhance ollama model url setting (#1322)

This commit is contained in:
Wendong-Fan 2026-02-21 11:00:53 +00:00 committed by GitHub
parent 96226ea01a
commit 2a65f6c8e8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -79,6 +79,9 @@ import zaiImage from '@/assets/model/zai.svg';
const LOCAL_PROVIDER_NAMES = ['ollama', 'vllm', 'sglang', 'lmstudio'];
const DEFAULT_OLLAMA_ENDPOINT = 'http://localhost:11434/v1';
const OLLAMA_ENDPOINT_AUTO_FIX_TITLE = 'Ollama endpoint updated';
const OLLAMA_ENDPOINT_AUTO_FIX_DESC =
'Added /v1 once. You can remove it if not needed.';
// Sidebar tab types
type SidebarTab =
@ -193,6 +196,8 @@ export default function SettingModels() {
const [ollamaModelsError, setOllamaModelsError] = useState<string | null>(
null
);
const [ollamaEndpointAutoFixedOnce, setOllamaEndpointAutoFixedOnce] =
useState(false);
// Fetch available models from Ollama API
const fetchOllamaModels = async (endpoint?: string) => {
@ -627,13 +632,65 @@ export default function SettingModels() {
};
// Local Model verification
const isOllamaEndpointMissingV1 = (endpoint: string): boolean => {
const trimmed = endpoint.trim();
if (!trimmed) return false;
try {
const normalizedPath = new URL(trimmed).pathname.replace(/\/+$/, '');
return !normalizedPath.endsWith('/v1');
} catch {
return !trimmed.replace(/\/+$/, '').endsWith('/v1');
}
};
const canAutoFixOllamaEndpoint = (endpoint: string): boolean => {
const trimmed = endpoint.trim();
if (!trimmed || !isOllamaEndpointMissingV1(trimmed)) return false;
try {
// Auto-fix only when endpoint has no extra path, e.g. http://localhost:11434
const normalizedPath = new URL(trimmed).pathname.replace(/\/+$/, '');
return normalizedPath === '';
} catch {
const withoutQueryOrHash = trimmed.split(/[?#]/)[0] || '';
const normalized = withoutQueryOrHash.replace(/\/+$/, '');
return !normalized.includes('/');
}
};
const appendV1ToEndpoint = (endpoint: string): string => {
const trimmed = endpoint.trim();
if (!trimmed) return trimmed;
try {
const parsed = new URL(trimmed);
const normalizedPath = parsed.pathname.replace(/\/+$/, '');
parsed.pathname = `${normalizedPath}/v1`.replace(/\/{2,}/g, '/');
return parsed.toString();
} catch {
return `${trimmed.replace(/\/+$/, '')}/v1`;
}
};
const handleLocalVerify = async () => {
setLocalVerifying(true);
setLocalError(null);
setLocalInputError(false);
const currentEndpoint = localEndpoints[localPlatform] || '';
let currentEndpoint = localEndpoints[localPlatform] || '';
const currentType = localTypes[localPlatform] || '';
// Fallback guard for fast save interactions: ensure one-time auto-fix
// still applies even if blur state hasn't committed yet.
if (
localPlatform === 'ollama' &&
!ollamaEndpointAutoFixedOnce &&
canAutoFixOllamaEndpoint(currentEndpoint)
) {
const fixedEndpoint = appendV1ToEndpoint(currentEndpoint);
currentEndpoint = fixedEndpoint;
setLocalEndpoints((prev) => ({
...prev,
[localPlatform]: fixedEndpoint,
}));
setOllamaEndpointAutoFixedOnce(true);
}
if (!currentEndpoint) {
setLocalError(t('setting.endpoint-url-can-not-be-empty'));
setLocalInputError(true);
@ -899,6 +956,7 @@ export default function SettingModels() {
setActiveModelIdx(null);
// Re-fetch Ollama models after reset
if (localPlatform === 'ollama') {
setOllamaEndpointAutoFixedOnce(false);
setOllamaModelsError(null);
fetchOllamaModels(DEFAULT_OLLAMA_ENDPOINT);
}
@ -1535,6 +1593,25 @@ export default function SettingModels() {
setOllamaModelsError(null);
}
}}
onBlur={(e) => {
if (
platform !== 'ollama' ||
ollamaEndpointAutoFixedOnce ||
!canAutoFixOllamaEndpoint(e.target.value)
) {
return;
}
const fixedEndpoint = appendV1ToEndpoint(e.target.value);
setLocalEndpoints((prev) => ({
...prev,
[platform]: fixedEndpoint,
}));
setOllamaEndpointAutoFixedOnce(true);
toast(OLLAMA_ENDPOINT_AUTO_FIX_TITLE, {
description: OLLAMA_ENDPOINT_AUTO_FIX_DESC,
closeButton: true,
});
}}
disabled={!localEnabled}
placeholder={
platform === 'ollama'