| import { useEffect, useState } from "react"; | |
| import System from "@/models/system"; | |
| import showToast from "@/utils/toast"; | |
| export default function useProviderEndpointAutoDiscovery({ | |
| provider = null, | |
| initialBasePath = "", | |
| initialAuthToken = null, | |
| ENDPOINTS = [], | |
| }) { | |
| const [loading, setLoading] = useState(false); | |
| const [basePath, setBasePath] = useState(initialBasePath); | |
| const [basePathValue, setBasePathValue] = useState(initialBasePath); | |
| const [authToken, setAuthToken] = useState(initialAuthToken); | |
| const [authTokenValue, setAuthTokenValue] = useState(initialAuthToken); | |
| const [autoDetectAttempted, setAutoDetectAttempted] = useState(false); | |
| const [showAdvancedControls, setShowAdvancedControls] = useState(true); | |
| async function autoDetect(isInitialAttempt = false) { | |
| setLoading(true); | |
| setAutoDetectAttempted(true); | |
| const possibleEndpoints = []; | |
| ENDPOINTS.forEach((endpoint) => { | |
| possibleEndpoints.push( | |
| new Promise((resolve, reject) => { | |
| System.customModels(provider, authTokenValue, endpoint, 2_000) | |
| .then((results) => { | |
| if (!results?.models || results.models.length === 0) | |
| throw new Error("No models"); | |
| resolve({ endpoint, models: results.models }); | |
| }) | |
| .catch(() => { | |
| reject(`${provider} @ ${endpoint} did not resolve.`); | |
| }); | |
| }) | |
| ); | |
| }); | |
| const { endpoint, models } = await Promise.any(possibleEndpoints) | |
| .then((resolved) => resolved) | |
| .catch(() => { | |
| console.error("All endpoints failed to resolve."); | |
| return { endpoint: null, models: null }; | |
| }); | |
| if (models !== null) { | |
| setBasePath(endpoint); | |
| setBasePathValue(endpoint); | |
| setLoading(false); | |
| showToast("Provider endpoint discovered automatically.", "success", { | |
| clear: true, | |
| }); | |
| setShowAdvancedControls(false); | |
| return; | |
| } | |
| setLoading(false); | |
| setShowAdvancedControls(true); | |
| showToast( | |
| "Couldn't automatically discover the provider endpoint. Please enter it manually.", | |
| "info", | |
| { clear: true } | |
| ); | |
| } | |
| function handleAutoDetectClick(e) { | |
| e.preventDefault(); | |
| autoDetect(); | |
| } | |
| function handleBasePathChange(e) { | |
| const value = e.target.value; | |
| setBasePathValue(value); | |
| } | |
| function handleBasePathBlur() { | |
| setBasePath(basePathValue); | |
| } | |
| function handleAuthTokenChange(e) { | |
| const value = e.target.value; | |
| setAuthTokenValue(value); | |
| } | |
| function handleAuthTokenBlur() { | |
| setAuthToken(authTokenValue); | |
| } | |
| useEffect(() => { | |
| if (!initialBasePath && !autoDetectAttempted) autoDetect(true); | |
| }, [initialBasePath, initialAuthToken, autoDetectAttempted]); | |
| return { | |
| autoDetecting: loading, | |
| autoDetectAttempted, | |
| showAdvancedControls, | |
| setShowAdvancedControls, | |
| basePath: { | |
| value: basePath, | |
| set: setBasePathValue, | |
| onChange: handleBasePathChange, | |
| onBlur: handleBasePathBlur, | |
| }, | |
| basePathValue: { | |
| value: basePathValue, | |
| set: setBasePathValue, | |
| }, | |
| authToken: { | |
| value: authToken, | |
| set: setAuthTokenValue, | |
| onChange: handleAuthTokenChange, | |
| onBlur: handleAuthTokenBlur, | |
| }, | |
| authTokenValue: { | |
| value: authTokenValue, | |
| set: setAuthTokenValue, | |
| }, | |
| handleAutoDetectClick, | |
| runAutoDetect: autoDetect, | |
| }; | |
| } | |