deepsite / hooks /useOpenRouterModels.ts
dr-data
Fix preview component: eliminate blinking, ensure HTML updates, add smooth transitions
dcd5e1d
import { useState, useEffect, useCallback } from 'react';
import { OpenRouterModel } from '../lib/openrouter';
interface UseOpenRouterModelsResult {
models: OpenRouterModel[];
filteredModels: OpenRouterModel[];
loading: boolean;
error: string | null;
searchTerm: string;
setSearchTerm: (term: string) => void;
selectedCategory: string;
setSelectedCategory: (category: string) => void;
refetch: () => Promise<void>;
categories: string[];
}
export function useOpenRouterModels(): UseOpenRouterModelsResult {
const [models, setModels] = useState<OpenRouterModel[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [searchTerm, setSearchTerm] = useState('');
const [selectedCategory, setSelectedCategory] = useState('all');
const fetchModels = useCallback(async () => {
if (loading) return; // Prevent multiple simultaneous requests
console.log('πŸ”„ Fetching OpenRouter models...');
setLoading(true);
setError(null);
try {
const url = new URL('/api/openrouter/models', window.location.origin);
console.log('πŸ“‘ Requesting:', url.toString());
const response = await fetch(url.toString());
console.log('πŸ“₯ Response status:', response.status);
const result = await response.json();
console.log('πŸ“‹ Response data:', result);
if (!result.success) {
throw new Error(result.error || 'Failed to fetch models');
}
console.log('βœ… Successfully fetched', result.data.length, 'models');
setModels(result.data);
} catch (err) {
console.error('❌ Error fetching models:', err);
setError(err instanceof Error ? err.message : 'Failed to fetch models');
} finally {
setLoading(false);
}
}, []); // Remove loading dependency to prevent infinite loop
useEffect(() => {
fetchModels();
}, [fetchModels]);
// Extract categories from model names/descriptions
const categories = [
'all',
...Array.from(new Set(
models
.map(model => {
const provider = model.id.split('/')[0];
return provider;
})
.filter(Boolean)
)).sort()
];
// Filter models based on search term and category
const filteredModels = models.filter(model => {
const matchesSearch = !searchTerm ||
model.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
model.id.toLowerCase().includes(searchTerm.toLowerCase()) ||
model.description.toLowerCase().includes(searchTerm.toLowerCase());
const matchesCategory = selectedCategory === 'all' ||
model.id.startsWith(selectedCategory + '/');
return matchesSearch && matchesCategory;
});
return {
models,
filteredModels,
loading,
error,
searchTerm,
setSearchTerm,
selectedCategory,
setSelectedCategory,
refetch: fetchModels,
categories
};
}