Download src/hooks/useModelList.ts from Amiel/deep-researcher: direct link, hf CLI and curl.
- Browser
- Download file 11.1 kB
-
https://huggingface.co/Amiel/deep-researcher/resolve/main/src/hooks/useModelList.ts
- Command line
-
hf download hf://Amiel/deep-researcher/src/hooks/useModelList.ts
-
curl -L -o useModelList.ts https://huggingface.co/Amiel/deep-researcher/resolve/main/src/hooks/useModelList.ts
11.1 kB
| import { useEffect, useState } from "react"; | |
| import { useSettingStore } from "@/store/setting"; | |
| import { | |
| GEMINI_BASE_URL, | |
| OPENROUTER_BASE_URL, | |
| OPENAI_BASE_URL, | |
| ANTHROPIC_BASE_URL, | |
| DEEPSEEK_BASE_URL, | |
| XAI_BASE_URL, | |
| MISTRAL_BASE_URL, | |
| POLLINATIONS_BASE_URL, | |
| OLLAMA_BASE_URL, | |
| } from "@/constants/urls"; | |
| import { multiApiKeyPolling } from "@/utils/model"; | |
| import { generateSignature } from "@/utils/signature"; | |
| import { completePath } from "@/utils/url"; | |
| interface GeminiModel { | |
| name: string; | |
| description: string; | |
| displayName: string; | |
| inputTokenLimit: number; | |
| maxTemperature?: number; | |
| outputTokenLimit: number; | |
| temperature?: number; | |
| topK?: number; | |
| topP?: number; | |
| supportedGenerationMethods: string[]; | |
| version: string; | |
| } | |
| interface OpenRouterModel { | |
| id: string; | |
| name: string; | |
| created: number; | |
| description: string; | |
| context_length: number; | |
| architecture: { | |
| modality: string; | |
| tokenizer: string; | |
| instruct_type?: string; | |
| }; | |
| top_provider: { | |
| context_length: number; | |
| max_completion_tokens: number; | |
| is_moderated: boolean; | |
| }; | |
| pricing: { | |
| prompt: string; | |
| completion: string; | |
| image: string; | |
| request: string; | |
| input_cache_read: string; | |
| input_cache_write: string; | |
| web_search: string; | |
| internal_reasoning: string; | |
| }; | |
| per_request_limits: Record<string, string> | null; | |
| } | |
| interface OpenAIModel { | |
| id: string; | |
| object: string; | |
| created: number; | |
| owned_by: string; | |
| } | |
| interface AnthropicModel { | |
| id: string; | |
| display_name: string; | |
| type: string; | |
| created_at: string; | |
| } | |
| interface MistralModel { | |
| id: string; | |
| object: string; | |
| created: number; | |
| owned_by: string; | |
| capabilities: { | |
| completion_chat: boolean; | |
| completion_fim: boolean; | |
| function_calling: boolean; | |
| fine_tuning: boolean; | |
| vision: boolean; | |
| classification: boolean; | |
| }; | |
| name: string; | |
| description: string; | |
| max_context_length: number; | |
| aliases: string[]; | |
| default_model_temperature: number; | |
| type: string; | |
| } | |
| interface OllamaModel { | |
| name: string; | |
| modified_at: string; | |
| size: number; | |
| digest: string; | |
| details: { | |
| format?: string; | |
| family?: string; | |
| families?: string | null; | |
| parameter_size?: string; | |
| quantization_level?: string; | |
| }; | |
| } | |
| function useModelList() { | |
| const [modelList, setModelList] = useState<string[]>([]); | |
| const { mode, provider } = useSettingStore.getState(); | |
| useEffect(() => { | |
| setModelList([]); | |
| }, [provider]); | |
| async function refresh(provider: string): Promise<string[]> { | |
| const { accessPassword } = useSettingStore.getState(); | |
| const accessKey = generateSignature(accessPassword, Date.now()); | |
| if (provider === "google") { | |
| const { apiKey = "", apiProxy } = useSettingStore.getState(); | |
| if (mode === "local" && !apiKey) { | |
| return []; | |
| } | |
| const key = multiApiKeyPolling(apiKey); | |
| const response = await fetch( | |
| mode === "local" | |
| ? completePath(apiProxy || GEMINI_BASE_URL, "/v1beta") + "/models" | |
| : "/api/ai/google/v1beta/models", | |
| { | |
| headers: { | |
| "x-goog-api-key": mode === "local" ? key : accessKey, | |
| }, | |
| } | |
| ); | |
| const { models = [] } = await response.json(); | |
| const newModelList = (models as GeminiModel[]) | |
| .filter( | |
| (item) => | |
| item.name.startsWith("models/gemini") && | |
| item.supportedGenerationMethods.includes("generateContent") | |
| ) | |
| .map((item) => item.name.replace("models/", "")); | |
| setModelList(newModelList); | |
| return newModelList; | |
| } else if (provider === "openrouter") { | |
| const { openRouterApiKey = "", openRouterApiProxy } = | |
| useSettingStore.getState(); | |
| if (mode === "local" && !openRouterApiKey) { | |
| return []; | |
| } | |
| const apiKey = multiApiKeyPolling(openRouterApiKey); | |
| const response = await fetch( | |
| mode === "local" | |
| ? completePath(openRouterApiProxy || OPENROUTER_BASE_URL, "/api/v1") + | |
| "/models" | |
| : "/api/ai/openrouter/v1/models", | |
| { | |
| headers: { | |
| authorization: `Bearer ${mode === "local" ? apiKey : accessKey}`, | |
| }, | |
| } | |
| ); | |
| const { data = [] } = await response.json(); | |
| const newModelList = (data as OpenRouterModel[]).map((item) => item.id); | |
| setModelList(newModelList); | |
| return newModelList; | |
| } else if (provider === "openai") { | |
| const { openAIApiKey = "", openAIApiProxy } = useSettingStore.getState(); | |
| if (mode === "local" && !openAIApiKey) { | |
| return []; | |
| } | |
| const apiKey = multiApiKeyPolling(openAIApiKey); | |
| const response = await fetch( | |
| mode === "local" | |
| ? completePath(openAIApiProxy || OPENAI_BASE_URL, "/v1") + "/models" | |
| : "/api/ai/openai/v1/models", | |
| { | |
| headers: { | |
| authorization: `Bearer ${mode === "local" ? apiKey : accessKey}`, | |
| }, | |
| } | |
| ); | |
| const { data = [] } = await response.json(); | |
| const newModelList = (data as OpenAIModel[]) | |
| .map((item) => item.id) | |
| .filter( | |
| (id) => | |
| !( | |
| id.startsWith("text") || | |
| id.startsWith("tts") || | |
| id.startsWith("whisper") || | |
| id.startsWith("dall-e") | |
| ) | |
| ); | |
| setModelList(newModelList); | |
| return newModelList; | |
| } else if (provider === "anthropic") { | |
| const { anthropicApiKey = "", anthropicApiProxy } = | |
| useSettingStore.getState(); | |
| if (mode === "local" && !anthropicApiKey) { | |
| return []; | |
| } | |
| const apiKey = multiApiKeyPolling(anthropicApiKey); | |
| const response = await fetch( | |
| mode === "local" | |
| ? completePath(anthropicApiProxy || ANTHROPIC_BASE_URL, "/v1") + | |
| "/models" | |
| : "/api/ai/anthropic/v1/models", | |
| { | |
| headers: { | |
| "Content-Type": "application/json", | |
| "x-api-key": mode === "local" ? apiKey : accessKey, | |
| "Anthropic-Version": "2023-06-01", | |
| // Avoid cors error | |
| "anthropic-dangerous-direct-browser-access": "true", | |
| }, | |
| } | |
| ); | |
| const { data = [] } = await response.json(); | |
| const newModelList = (data as AnthropicModel[]).map((item) => item.id); | |
| setModelList(newModelList); | |
| return newModelList; | |
| } else if (provider === "deepseek") { | |
| const { deepseekApiKey = "", deepseekApiProxy } = | |
| useSettingStore.getState(); | |
| if (mode === "local" && !deepseekApiKey) { | |
| return []; | |
| } | |
| const apiKey = multiApiKeyPolling(deepseekApiKey); | |
| const response = await fetch( | |
| mode === "local" | |
| ? completePath(deepseekApiProxy || DEEPSEEK_BASE_URL, "/v1") + | |
| "/models" | |
| : "/api/ai/deepseek/v1/models", | |
| { | |
| headers: { | |
| authorization: `Bearer ${mode === "local" ? apiKey : accessKey}`, | |
| }, | |
| } | |
| ); | |
| const { data = [] } = await response.json(); | |
| const newModelList = (data as OpenAIModel[]).map((item) => item.id); | |
| setModelList(newModelList); | |
| return newModelList; | |
| } else if (provider === "xai") { | |
| const { xAIApiKey = "", xAIApiProxy } = useSettingStore.getState(); | |
| if (mode === "local" && !xAIApiKey) { | |
| return []; | |
| } | |
| const apiKey = multiApiKeyPolling(xAIApiKey); | |
| const response = await fetch( | |
| mode === "local" | |
| ? completePath(xAIApiProxy || XAI_BASE_URL, "/v1") + "/models" | |
| : "/api/ai/xai/v1/models", | |
| { | |
| headers: { | |
| authorization: `Bearer ${mode === "local" ? apiKey : accessKey}`, | |
| }, | |
| } | |
| ); | |
| const { data = [] } = await response.json(); | |
| const newModelList = (data as OpenAIModel[]) | |
| .map((item) => item.id) | |
| .filter((id) => !id.includes("image")); | |
| setModelList(newModelList); | |
| return newModelList; | |
| } else if (provider === "mistral") { | |
| const { mistralApiKey = "", mistralApiProxy } = | |
| useSettingStore.getState(); | |
| if (mode === "local" && !mistralApiKey) { | |
| return []; | |
| } | |
| const apiKey = multiApiKeyPolling(mistralApiKey); | |
| const response = await fetch( | |
| mode === "local" | |
| ? completePath(mistralApiProxy || MISTRAL_BASE_URL, "/v1") + "/models" | |
| : "/api/ai/mistral/v1/models", | |
| { | |
| headers: { | |
| authorization: `Bearer ${mode === "local" ? apiKey : accessKey}`, | |
| }, | |
| } | |
| ); | |
| const { data = [] } = await response.json(); | |
| const newModelList = (data as MistralModel[]) | |
| .filter((item) => item.capabilities.completion_chat) | |
| .map((item) => item.id); | |
| setModelList(newModelList); | |
| return newModelList; | |
| } else if (provider === "openaicompatible") { | |
| const { openAICompatibleApiKey = "", openAICompatibleApiProxy } = | |
| useSettingStore.getState(); | |
| if (mode === "local" && !openAICompatibleApiKey) { | |
| return []; | |
| } | |
| const apiKey = multiApiKeyPolling(openAICompatibleApiKey); | |
| const response = await fetch( | |
| mode === "local" | |
| ? completePath(openAICompatibleApiProxy, "/v1") + "/models" | |
| : "/api/ai/openaicompatible/v1/models", | |
| { | |
| headers: { | |
| authorization: `Bearer ${mode === "local" ? apiKey : accessKey}`, | |
| }, | |
| } | |
| ); | |
| const { data = [] } = await response.json(); | |
| const newModelList = (data as OpenAIModel[]).map((item) => item.id); | |
| setModelList(newModelList); | |
| return newModelList; | |
| } else if (provider === "pollinations") { | |
| const { pollinationsApiProxy } = useSettingStore.getState(); | |
| const headers = new Headers(); | |
| if (mode === "proxy") headers.set("Authorization", `Bearer ${accessKey}`); | |
| const response = await fetch( | |
| mode === "proxy" | |
| ? "/api/ai/pollinations/models" | |
| : completePath(pollinationsApiProxy || POLLINATIONS_BASE_URL) + | |
| "/models", | |
| { | |
| headers, | |
| } | |
| ); | |
| const { data = [] } = await response.json(); | |
| const newModelList = (data as OpenAIModel[]) | |
| .map((item) => item.id) | |
| .filter((name) => !name.includes("audio")); | |
| setModelList(newModelList); | |
| return newModelList; | |
| } else if (provider === "ollama") { | |
| const { ollamaApiProxy } = useSettingStore.getState(); | |
| const headers = new Headers(); | |
| if (mode === "proxy") headers.set("Authorization", `Bearer ${accessKey}`); | |
| const response = await fetch( | |
| mode === "proxy" | |
| ? "/api/ai/ollama/api/tags" | |
| : completePath(ollamaApiProxy || OLLAMA_BASE_URL, "/api") + "/tags", | |
| { | |
| headers, | |
| } | |
| ); | |
| const { models = [] } = await response.json(); | |
| const newModelList = (models as OllamaModel[]).map((item) => item.name); | |
| setModelList(newModelList); | |
| return newModelList; | |
| } else { | |
| return []; | |
| } | |
| } | |
| return { | |
| modelList, | |
| refresh, | |
| }; | |
| } | |
| export default useModelList; | |