/*
Copyright (C) 2023-2026 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
For commercial licensing, please contact support@quantumnous.com
*/
import { useCallback, useEffect, useRef, useState } from 'react'
import { createServerError } from '@/lib/server-error-message'
import { fetchModels, fetchUpstreamModels } from '../api'
type DiscoveryState = {
status: 'idle' | 'loading' | 'success' | 'error' | 'stale'
models: string[]
error?: unknown
}
export type ChannelModelDiscoveryRequest =
| { kind: 'saved'; channelId: number }
| { kind: 'preview'; data: Parameters[0] }
type ChannelModelDiscoveryProps = {
enabled: boolean
request: ChannelModelDiscoveryRequest
}
export function useChannelModelDiscovery(props: ChannelModelDiscoveryProps) {
const [state, setState] = useState({
status: 'idle',
models: [],
})
const sequence = useRef(0)
useEffect(() => {
sequence.current += 1
setState((previous) => {
if (previous.status === 'idle') return previous
if (!props.enabled) return { status: 'idle', models: [] }
return { status: 'stale', models: previous.models }
})
return () => {
sequence.current += 1
}
}, [props.enabled, props.request])
const fetch = useCallback(async () => {
if (!props.enabled) return
const requestSequence = ++sequence.current
setState((previous) => ({ status: 'loading', models: previous.models }))
try {
const response =
props.request.kind === 'saved'
? await fetchUpstreamModels(props.request.channelId)
: await fetchModels(props.request.data)
if (requestSequence !== sequence.current) return
if (!response.success) {
throw createServerError(response, 'Failed to fetch models')
}
setState({ status: 'success', models: response.data ?? [] })
} catch (error) {
if (requestSequence !== sequence.current) return
setState((previous) => ({
status: 'error',
models: previous.models,
error,
}))
}
}, [props.enabled, props.request])
return { ...state, fetch }
}