File size: 3,424 Bytes
f8b5d42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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,
  };
}