Spaces:
Paused
Paused
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 | |
| }; | |
| } | |