83 lines
3.9 KiB
TypeScript
83 lines
3.9 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import { ApiClient } from '../lib/api-client'
|
|
import { useAppSettings } from '../contexts/AppSettingsContext'
|
|
|
|
export type EnhanceProvider = 'local' | 'api'
|
|
|
|
interface UsePromptEnhancerProviderResult {
|
|
// Local requires the Gemma text-encoder checkpoint to be downloaded AND local generation to
|
|
// actually be usable this run (e.g. not memory-constrained into API-only mode); API requires a
|
|
// stored Gemini key to actually run, but the option stays selectable without one so Enhance
|
|
// can send the user to Settings instead of hiding the choice.
|
|
hasLocalTextEncoder: boolean
|
|
hasGeminiApiKey: boolean
|
|
// The provider Enhance will actually use: the persisted preference when it's currently
|
|
// choosable. API remains choosable without a key (clicking Enhance then opens Settings).
|
|
// Local that's temporarily unavailable (e.g. memory-constrained run) falls back silently —
|
|
// it does NOT overwrite the persisted preference, which only an explicit setProviderPreference
|
|
// call changes.
|
|
provider: EnhanceProvider
|
|
// Shown when local Enhance is available, so the user can still pick API (Gemini) before
|
|
// they've added a key. Hidden when local isn't an option — the button is already API-only.
|
|
canToggleProvider: boolean
|
|
setProviderPreference: (provider: EnhanceProvider) => void
|
|
}
|
|
|
|
// Single source of truth for which prompt-enhancer provider (local Gemma text encoder vs.
|
|
// Gemini's hosted API) is available and which one Enhance should use. `enabled` gates the local
|
|
// checkpoint lookup so it only fires once the enhancer could plausibly be shown for the current
|
|
// mode.
|
|
export function usePromptEnhancerProvider(enabled: boolean): UsePromptEnhancerProviderResult {
|
|
const {
|
|
settings: { hasGeminiApiKey, promptEnhancerProviderPreference },
|
|
updateSettings,
|
|
forceApiGenerations,
|
|
modelsVersion,
|
|
} = useAppSettings()
|
|
|
|
const [isLocalEncoderUsable, setIsLocalEncoderUsable] = useState(false)
|
|
useEffect(() => {
|
|
if (!enabled) return
|
|
let cancelled = false
|
|
void ApiClient.getTextEncoderRecommendation().then((result) => {
|
|
// Deliberately not cp_to_download: the encoder that runs generations isn't always the one
|
|
// that can enhance (LTX 2.5's encodes only, and enhances from a separate checkpoint), so
|
|
// the backend reports enhancer availability on its own.
|
|
if (!cancelled) {
|
|
setIsLocalEncoderUsable(result.ok && result.data.local_enhancement_supported)
|
|
}
|
|
})
|
|
return () => { cancelled = true }
|
|
// modelsVersion: the enhancer is a download the user can make mid-session, and Enhance should
|
|
// become available without a restart.
|
|
}, [enabled, modelsVersion])
|
|
|
|
// Downloaded isn't enough on its own — forceApiGenerations is the pure "insufficient memory
|
|
// for local models this run" signal (deliberately NOT shouldVideoGenerateWithLtxApi, which
|
|
// also folds in the user's own preference to use the LTX API for VIDEO specifically — that's
|
|
// unrelated to whether the much smaller Gemma text encoder can run locally right now).
|
|
const hasLocalTextEncoder = isLocalEncoderUsable && !forceApiGenerations
|
|
const canToggleProvider = hasLocalTextEncoder
|
|
|
|
// Default to local when the user hasn't made an explicit choice, or when they asked for
|
|
// local and it's currently usable. API preference is honored even without a Gemini key so
|
|
// the Enhance (API) option isn't silently replaced by local.
|
|
const provider: EnhanceProvider =
|
|
promptEnhancerProviderPreference === 'api' ? 'api'
|
|
: promptEnhancerProviderPreference === 'local' && hasLocalTextEncoder ? 'local'
|
|
: hasLocalTextEncoder ? 'local'
|
|
: 'api'
|
|
|
|
const setProviderPreference = (next: EnhanceProvider) => {
|
|
updateSettings({ promptEnhancerProviderPreference: next })
|
|
}
|
|
|
|
return {
|
|
hasLocalTextEncoder,
|
|
hasGeminiApiKey,
|
|
provider,
|
|
canToggleProvider,
|
|
setProviderPreference,
|
|
}
|
|
}
|