fix: fix refreshing custom models

This commit is contained in:
Vukasin 2025-05-22 18:04:55 +02:00
parent 2d6ec3d59d
commit 8747c0fe42
4 changed files with 98 additions and 29 deletions

View File

@ -247,11 +247,17 @@ export const useModelSelection = () => {
? 'active'
: 'no_subscription';
// Function to refresh custom models from localStorage
const refreshCustomModels = () => {
if (isLocalMode() && typeof window !== 'undefined') {
const freshCustomModels = getCustomModels();
setCustomModels(freshCustomModels);
}
};
// Load custom models from localStorage
useEffect(() => {
if (isLocalMode() && typeof window !== 'undefined') {
setCustomModels(getCustomModels());
}
refreshCustomModels();
}, []);
// Generate model options list with consistent structure
@ -417,21 +423,37 @@ export const useModelSelection = () => {
// Handle model selection change
const handleModelChange = (modelId: string) => {
const modelOption = MODEL_OPTIONS.find(option => option.id === modelId);
console.log('handleModelChange', modelId);
// Refresh custom models from localStorage to ensure we have the latest
if (isLocalMode()) {
refreshCustomModels();
}
// First check if it's a custom model in local mode
const isCustomModel = isLocalMode() && customModels.some(model => model.id === modelId);
// Check if model exists
// Then check if it's in standard MODEL_OPTIONS
const modelOption = MODEL_OPTIONS.find(option => option.id === modelId);
// Check if model exists in either custom models or standard options
if (!modelOption && !isCustomModel) {
console.warn('Model not found in options:', modelId);
console.warn('Model not found in options:', modelId, MODEL_OPTIONS, isCustomModel, customModels);
// Reset to default model when the selected model is not found
const defaultModel = isLocalMode() ? DEFAULT_PREMIUM_MODEL_ID : DEFAULT_FREE_MODEL_ID;
setSelectedModel(defaultModel);
saveModelPreference(defaultModel);
return;
}
// Check access permissions (except for custom models in local mode)
if (!isCustomModel && !isLocalMode() &&
!canAccessModel(subscriptionStatus, modelOption?.requiresSubscription ?? false)) {
console.warn('Model not accessible:', modelId);
return;
}
console.log('setting selected model', modelId);
setSelectedModel(modelId);
saveModelPreference(modelId);
};
@ -444,12 +466,15 @@ export const useModelSelection = () => {
return {
selectedModel,
setSelectedModel: handleModelChange,
setSelectedModel: (modelId: string) => {
handleModelChange(modelId);
},
subscriptionStatus,
availableModels,
allModels: MODEL_OPTIONS, // Already pre-sorted
customModels,
getActualModelId,
refreshCustomModels,
canAccessModel: (modelId: string) => {
if (isLocalMode()) return true;
const model = MODEL_OPTIONS.find(m => m.id === modelId);

View File

@ -82,6 +82,7 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
allModels: modelOptions,
canAccessModel,
getActualModelId,
refreshCustomModels,
} = useModelSelection();
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
@ -233,6 +234,7 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
modelOptions={modelOptions}
subscriptionStatus={subscriptionStatus}
canAccessModel={canAccessModel}
refreshCustomModels={refreshCustomModels}
/>
</CardContent>
</div>

View File

@ -36,7 +36,8 @@ interface MessageInputProps {
onModelChange: (model: string) => void;
modelOptions: any[];
subscriptionStatus: SubscriptionStatus;
canAccessModel: (model: string) => boolean;
canAccessModel: (modelId: string) => boolean;
refreshCustomModels?: () => void;
}
export const MessageInput = forwardRef<HTMLTextAreaElement, MessageInputProps>(
@ -66,6 +67,7 @@ export const MessageInput = forwardRef<HTMLTextAreaElement, MessageInputProps>(
modelOptions,
subscriptionStatus,
canAccessModel,
refreshCustomModels,
},
ref,
) => {
@ -148,6 +150,7 @@ export const MessageInput = forwardRef<HTMLTextAreaElement, MessageInputProps>(
modelOptions={modelOptions}
subscriptionStatus={subscriptionStatus}
canAccessModel={canAccessModel}
refreshCustomModels={refreshCustomModels}
/>
<Button
type="submit"

View File

@ -44,6 +44,7 @@ interface ModelSelectorProps {
modelOptions: ModelOption[];
canAccessModel: (modelId: string) => boolean;
subscriptionStatus: SubscriptionStatus;
refreshCustomModels?: () => void;
}
export const ModelSelector: React.FC<ModelSelectorProps> = ({
@ -52,6 +53,7 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
modelOptions,
canAccessModel,
subscriptionStatus,
refreshCustomModels,
}) => {
const [paywallOpen, setPaywallOpen] = useState(false);
const [lockedModel, setLockedModel] = useState<string | null>(null);
@ -96,17 +98,30 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
});
});
// Then add custom models, overriding any with the same ID
currentCustomModels.forEach(model => {
if (!modelMap.has(model.id)) {
modelMap.set(model.id, {
...model,
requiresSubscription: false,
top: false,
isCustom: true
});
}
});
// Then add custom models from the current customModels state (not from props)
// This ensures we're using the most up-to-date list of custom models
if (isLocalMode()) {
// Get current custom models from state (not from storage)
customModels.forEach(model => {
// Only add if it doesn't exist or mark it as a custom model if it does
if (!modelMap.has(model.id)) {
modelMap.set(model.id, {
id: model.id,
label: model.label || formatModelName(model.id),
requiresSubscription: false,
top: false,
isCustom: true
});
} else {
// If it already exists (rare case), mark it as a custom model
const existingModel = modelMap.get(model.id);
modelMap.set(model.id, {
...existingModel,
isCustom: true
});
}
});
}
// Convert map back to array
const enhancedModelOptions = Array.from(modelMap.values());
@ -255,10 +270,13 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
// First close the dialog to prevent UI issues
closeCustomModelDialog();
// Create the new model object
const newModel = { id: modelId, label: modelLabel };
// Update models array (add new or update existing)
const updatedModels = dialogMode === 'add'
? [...customModels, { id: modelId, label: modelLabel }]
: customModels.map(model => model.id === editingModelId ? { id: modelId, label: modelLabel } : model);
? [...customModels, newModel]
: customModels.map(model => model.id === editingModelId ? newModel : model);
// Save to localStorage first
try {
@ -270,6 +288,11 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
// Update state with new models
setCustomModels(updatedModels);
// Refresh custom models in the parent hook if the function is available
if (refreshCustomModels) {
refreshCustomModels();
}
// Handle model selection changes
if (dialogMode === 'add') {
// Always select newly added models
@ -334,6 +357,11 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
// Update state with the new list
setCustomModels(updatedCustomModels);
// Refresh custom models in the parent hook if the function is available
if (refreshCustomModels) {
refreshCustomModels();
}
// Check if we need to change the selected model
if (selectedModel === modelId) {
const defaultModel = isLocalMode() ? DEFAULT_PREMIUM_MODEL_ID : DEFAULT_FREE_MODEL_ID;
@ -345,18 +373,29 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
}
}
// Force dropdown to close to ensure proper refresh on next open
// Force dropdown to close
setIsOpen(false);
// Force a UI refresh by scheduling a state update after React completes this render cycle
// Update the modelMap and recreate enhancedModelOptions on next render
// This will force a complete refresh of the model list
setTimeout(() => {
setIsOpen(false);
}, 0);
// Force React to fully re-evaluate the component with fresh data
setHighlightedIndex(-1);
// Reopen dropdown with fresh data if it was open
if (isOpen) {
setIsOpen(false);
setTimeout(() => setIsOpen(true), 50);
}
}, 10);
};
const renderModelOption = (opt: any, index: number) => {
// Custom models are always accessible in local mode
const isCustom = opt.isCustom || customModels.some(model => model.id === opt.id);
// More accurate check for custom models - use the actual customModels array
// from both the opt.isCustom flag and by checking if it exists in customModels
const isCustom = Boolean(opt.isCustom) ||
(isLocalMode() && customModels.some(model => model.id === opt.id));
const accessible = isCustom ? true : canAccessModel(opt.id);
// Fix the highlighting logic to use the index parameter instead of searching in filteredOptions
@ -460,7 +499,7 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
setIsOpen(false);
setTimeout(() => setIsOpen(true), 10);
}
}, [customModels]);
}, [customModels, modelOptions]); // Also depend on modelOptions to refresh when parent changes
return (
<div className="relative">