feat: enhance Ollama URL handling in TextProvider and PresentonMode components, adding custom URL options and improving user experience
This commit is contained in:
parent
86ea9a91da
commit
22ee90664c
3 changed files with 153 additions and 49 deletions
|
|
@ -5,7 +5,7 @@ import { Switch } from '@/components/ui/switch';
|
|||
import { cn } from '@/lib/utils';
|
||||
import { LLMConfig } from '@/types/llm_config';
|
||||
import { LLM_PROVIDERS } from '@/utils/providerConstants';
|
||||
import { Check, ChevronsUpDown, Loader2, Eye, EyeOff, ChevronUp } from 'lucide-react';
|
||||
import { Check, Loader2, Eye, EyeOff, ChevronUp } from 'lucide-react';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { toast } from 'sonner';
|
||||
|
||||
|
|
@ -68,6 +68,7 @@ const TextProvider = ({
|
|||
const currentApiKey = currentApiKeyField ? ((llmConfig as Record<string, unknown>)[currentApiKeyField] as string || '') : '';
|
||||
const currentCustomUrl = llmConfig.CUSTOM_LLM_URL || '';
|
||||
const currentOllamaUrl = llmConfig.OLLAMA_URL || '';
|
||||
const useCustomOllamaUrl = !!llmConfig.USE_CUSTOM_URL;
|
||||
const modelLabel = selectedProviderMeta?.label || selectedProvider;
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -304,28 +305,71 @@ const TextProvider = ({
|
|||
</div>
|
||||
<div className="relative flex flex-col justify-end items-end w-[205px] ">
|
||||
<div className="flex flex-col justify-start ">
|
||||
<label className="block text-sm font-medium capitalize text-gray-700 mb-2">
|
||||
{selectedProvider === 'ollama' ? 'Ollama URL' : selectedProvider === 'custom' ? 'Custom LLM API Key' : `${llmConfig.LLM} API Key`}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type={selectedProvider === 'ollama' ? 'text' : showApiKey ? 'text' : 'password'}
|
||||
|
||||
value={selectedProvider === 'ollama' ? currentOllamaUrl : currentApiKey}
|
||||
onChange={(e) => onApiKeyChange(selectedProvider, e.target.value)}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder={selectedProvider === 'ollama' ? 'http://localhost:11434' : `Enter your ${llmConfig.LLM} API key`}
|
||||
/>
|
||||
{selectedProvider !== 'ollama' && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowApiKey((prev) => !prev)}
|
||||
className='absolute right-2 top-1/2 -translate-y-1/2 bg-white px-2 py-1 cursor-pointer'
|
||||
>
|
||||
{showApiKey ? <Eye className='w-4 h-4 text-gray-500' /> : <EyeOff className='w-4 h-4 text-gray-500' />}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{selectedProvider === 'ollama' ? (
|
||||
<>
|
||||
{!useCustomOllamaUrl ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onInputChange(true, 'USE_CUSTOM_URL');
|
||||
if (!currentOllamaUrl) {
|
||||
onInputChange('http://localhost:11434', 'OLLAMA_URL');
|
||||
}
|
||||
}}
|
||||
className="mt-8 py-2.5 bg-[#EDEEEF] px-3.5 w-fit rounded-[48px] text-xs font-semibold text-[#101323] transition-all duration-200 border border-[#EDEEEF] hover:bg-[#E8F0FF]/90 focus:ring-2 focus:ring-blue-500/20"
|
||||
>
|
||||
Use Ollama URL
|
||||
</button>
|
||||
) : (
|
||||
<>
|
||||
<label className="block text-sm font-medium capitalize text-gray-700 mb-2">
|
||||
Ollama URL
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type="text"
|
||||
value={currentOllamaUrl}
|
||||
onChange={(e) => onApiKeyChange(selectedProvider, e.target.value)}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="http://localhost:11434"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onInputChange(false, 'USE_CUSTOM_URL');
|
||||
onInputChange('http://localhost:11434', 'OLLAMA_URL');
|
||||
}}
|
||||
className="mt-2 text-xs font-medium text-[#4B5563] underline underline-offset-2"
|
||||
>
|
||||
Use default Ollama URL
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<label className="block text-sm font-medium capitalize text-gray-700 mb-2">
|
||||
{selectedProvider === 'custom' ? 'Custom LLM API Key' : `${llmConfig.LLM} API Key`}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type={showApiKey ? 'text' : 'password'}
|
||||
value={currentApiKey}
|
||||
onChange={(e) => onApiKeyChange(selectedProvider, e.target.value)}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder={`Enter your ${llmConfig.LLM} API key`}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowApiKey((prev) => !prev)}
|
||||
className='absolute right-2 top-1/2 -translate-y-1/2 bg-white px-2 py-1 cursor-pointer'
|
||||
>
|
||||
{showApiKey ? <Eye className='w-4 h-4 text-gray-500' /> : <EyeOff className='w-4 h-4 text-gray-500' />}
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{selectedProvider === 'custom' && (
|
||||
<input
|
||||
type="text"
|
||||
|
|
|
|||
|
|
@ -99,6 +99,8 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
|
|||
|
||||
const currentApiKey = currentApiKeyField ? ((llmConfig as Record<string, unknown>)[currentApiKeyField] as string || '') : '';
|
||||
const currentModel = currentModelField ? ((llmConfig as Record<string, unknown>)[currentModelField] as string || '') : '';
|
||||
const currentOllamaUrl = llmConfig.OLLAMA_URL || '';
|
||||
const useCustomOllamaUrl = !!llmConfig.USE_CUSTOM_URL;
|
||||
|
||||
const fetchAvailableModels = async () => {
|
||||
if (llmConfig.LLM === 'openai' && !currentApiKey) return;
|
||||
|
|
@ -309,6 +311,11 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
|
|||
return 0;
|
||||
}, [downloadingModel?.downloaded, downloadingModel?.size]);
|
||||
|
||||
useEffect(() => {
|
||||
if (llmConfig.LLM === 'ollama' && !modelsChecked && !modelsLoading) {
|
||||
fetchAvailableModels();
|
||||
}
|
||||
}, [llmConfig.LLM, modelsChecked, modelsLoading]);
|
||||
|
||||
return (
|
||||
<div className='w-full max-w-[640px] font-syne'>
|
||||
|
|
@ -414,31 +421,77 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
|
|||
</div>
|
||||
<div className="relative flex flex-col justify-end items-end w-full ">
|
||||
<div className="flex flex-col justify-start w-full ">
|
||||
<label className="block text-sm font-medium capitalize text-gray-700 mb-2">
|
||||
{llmConfig.LLM === 'ollama' ? 'Ollama URL' : llmConfig.LLM === 'custom' ? 'Custom LLM API Key' : `${llmConfig.LLM} API Key`}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type={llmConfig.LLM === 'ollama' ? 'text' : showApiKey ? 'text' : 'password'}
|
||||
|
||||
value={llmConfig.LLM === 'ollama' ? llmConfig.OLLAMA_URL : currentApiKey}
|
||||
onChange={(e) => setLlmConfig(prev => ({
|
||||
...prev,
|
||||
[currentApiKeyField]: e.target.value
|
||||
}))}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder={llmConfig.LLM === 'ollama' ? 'http://localhost:11434' : `Enter your ${llmConfig.LLM} API key`}
|
||||
/>
|
||||
{llmConfig.LLM !== 'ollama' && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowApiKey((prev) => !prev)}
|
||||
className='absolute right-2 top-1/2 -translate-y-1/2 bg-white px-2 py-1 cursor-pointer'
|
||||
>
|
||||
{showApiKey ? <Eye className='w-4 h-4 text-gray-500' /> : <EyeOff className='w-4 h-4 text-gray-500' />}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{llmConfig.LLM === 'ollama' ? (
|
||||
<>
|
||||
{!useCustomOllamaUrl ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setLlmConfig(prev => ({
|
||||
...prev,
|
||||
USE_CUSTOM_URL: true,
|
||||
OLLAMA_URL: prev.OLLAMA_URL || 'http://localhost:11434'
|
||||
}))}
|
||||
className="mt-8 py-2.5 bg-[#EDEEEF] px-3.5 w-fit rounded-[48px] text-xs font-semibold text-[#101323] transition-all duration-200 border border-[#EDEEEF] hover:bg-[#E8F0FF]/90 focus:ring-2 focus:ring-blue-500/20"
|
||||
>
|
||||
Use Ollama URL
|
||||
</button>
|
||||
) : (
|
||||
<>
|
||||
<label className="block text-sm font-medium capitalize text-gray-700 mb-2">
|
||||
Ollama URL
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type="text"
|
||||
value={currentOllamaUrl}
|
||||
onChange={(e) => setLlmConfig(prev => ({
|
||||
...prev,
|
||||
OLLAMA_URL: e.target.value
|
||||
}))}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="http://localhost:11434"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setLlmConfig(prev => ({
|
||||
...prev,
|
||||
USE_CUSTOM_URL: false,
|
||||
OLLAMA_URL: 'http://localhost:11434'
|
||||
}))}
|
||||
className="mt-2 text-xs font-medium text-[#4B5563] underline underline-offset-2"
|
||||
>
|
||||
Use default Ollama URL
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<label className="block text-sm font-medium capitalize text-gray-700 mb-2">
|
||||
{llmConfig.LLM === 'custom' ? 'Custom LLM API Key' : `${llmConfig.LLM} API Key`}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type={showApiKey ? 'text' : 'password'}
|
||||
value={currentApiKey}
|
||||
onChange={(e) => setLlmConfig(prev => ({
|
||||
...prev,
|
||||
[currentApiKeyField]: e.target.value
|
||||
}))}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder={`Enter your ${llmConfig.LLM} API key`}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowApiKey((prev) => !prev)}
|
||||
className='absolute right-2 top-1/2 -translate-y-1/2 bg-white px-2 py-1 cursor-pointer'
|
||||
>
|
||||
{showApiKey ? <Eye className='w-4 h-4 text-gray-500' /> : <EyeOff className='w-4 h-4 text-gray-500' />}
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{llmConfig.LLM === 'custom' && (
|
||||
<input
|
||||
type="text"
|
||||
|
|
@ -579,7 +632,7 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
|
|||
<div className='flex justify-end items-center'>
|
||||
<Switch
|
||||
checked={!llmConfig.DISABLE_IMAGE_GENERATION}
|
||||
className=''
|
||||
className='data-[state=checked]:bg-[#4791FF] data-[state=unchecked]:bg-gray-400'
|
||||
onCheckedChange={(checked) => setLlmConfig(prev => ({
|
||||
...prev,
|
||||
DISABLE_IMAGE_GENERATION: !checked
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ export interface LLMProviderOption {
|
|||
model_value?: string;
|
||||
model_label?: string;
|
||||
url?: string;
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
export const IMAGE_PROVIDERS: Record<string, ImageProviderOption> = {
|
||||
|
|
@ -97,33 +98,39 @@ export const LLM_PROVIDERS: Record<string, LLMProviderOption> = {
|
|||
label: "OpenAI",
|
||||
description: "OpenAI's latest text generation model",
|
||||
url: "https://api.openai.com/v1",
|
||||
icon: "/icons/openai.png",
|
||||
},
|
||||
google: {
|
||||
value: "google",
|
||||
label: "Google",
|
||||
description: "Google's primary text generation model",
|
||||
url: "https://api.google.com/v1",
|
||||
icon: "/icons/google.png",
|
||||
},
|
||||
anthropic: {
|
||||
value: "anthropic",
|
||||
label: "Anthropic",
|
||||
description: "Anthropic's Claude models",
|
||||
url: "https://api.anthropic.com/v1",
|
||||
icon: "/icons/anthropic.png",
|
||||
},
|
||||
ollama: {
|
||||
value: "ollama",
|
||||
label: "Ollama",
|
||||
description: "Ollama's primary text generation model",
|
||||
icon: "/icons/ollama.png",
|
||||
},
|
||||
custom: {
|
||||
value: "custom",
|
||||
label: "Custom",
|
||||
description: "Custom LLM",
|
||||
icon: "/icons/custom.png",
|
||||
},
|
||||
codex: {
|
||||
value: "codex",
|
||||
label: "ChatGPT",
|
||||
description: "ChatGPT Plus/Pro via OAuth",
|
||||
icon: "/icons/chatgpt.png",
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue