Create standalone browser port of LTX Athena with authenticated native API transport
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { ApiClient, type ApiSuccessOf } from '../lib/api-client'
|
||||
import { logger } from '../lib/logger'
|
||||
|
||||
type HfAuthStatus = ApiSuccessOf<'getHuggingFaceAuthStatus'>['status']
|
||||
|
||||
interface UseHfAuthResult {
|
||||
hfAuthStatus: HfAuthStatus
|
||||
hfAuthPolling: boolean
|
||||
startHuggingFaceLogin: () => Promise<void>
|
||||
handleHuggingFaceLogout: () => Promise<void>
|
||||
}
|
||||
|
||||
const NOOP = async () => {}
|
||||
|
||||
export function useHfAuth(enabled: boolean): UseHfAuthResult {
|
||||
// Used for gated downloads (LTX 2.5 base models, catalog LoRAs / IC-LoRAs).
|
||||
const [hfAuthStatus, setHfAuthStatus] = useState<HfAuthStatus>('not_authenticated')
|
||||
const [hfAuthPolling, setHfAuthPolling] = useState(false)
|
||||
|
||||
// One-time check when enabled becomes true
|
||||
useEffect(() => {
|
||||
if (!enabled) return
|
||||
const checkAuth = async () => {
|
||||
const result = await ApiClient.getHuggingFaceAuthStatus()
|
||||
if (!result.ok) {
|
||||
logger.error(`HF auth status check failed: ${result.error.message}`)
|
||||
return
|
||||
}
|
||||
setHfAuthStatus(result.data.status)
|
||||
}
|
||||
void checkAuth()
|
||||
}, [enabled])
|
||||
|
||||
// Poll while waiting for user to complete auth in browser
|
||||
useEffect(() => {
|
||||
if (!hfAuthPolling) return
|
||||
const interval = setInterval(async () => {
|
||||
const result = await ApiClient.getHuggingFaceAuthStatus()
|
||||
if (!result.ok) {
|
||||
logger.error(`HF auth status check failed: ${result.error.message}`)
|
||||
return
|
||||
}
|
||||
const { status } = result.data
|
||||
setHfAuthStatus(status)
|
||||
if (status === 'authenticated') setHfAuthPolling(false)
|
||||
}, 2000)
|
||||
return () => clearInterval(interval)
|
||||
}, [hfAuthPolling])
|
||||
|
||||
const startHuggingFaceLogin = useCallback(async () => {
|
||||
const result = await ApiClient.startHuggingFaceLogin()
|
||||
if (!result.ok) {
|
||||
logger.error(`HF login failed: ${result.error.message}`)
|
||||
return
|
||||
}
|
||||
|
||||
const params = result.data
|
||||
setHfAuthPolling(true)
|
||||
await window.electronAPI.openHuggingFaceAuth({
|
||||
clientId: params.client_id,
|
||||
redirectUri: params.redirect_uri,
|
||||
scope: params.scope,
|
||||
state: params.state,
|
||||
codeChallenge: params.code_challenge,
|
||||
codeChallengeMethod: params.code_challenge_method,
|
||||
})
|
||||
}, [])
|
||||
|
||||
const handleHuggingFaceLogout = useCallback(async () => {
|
||||
const result = await ApiClient.huggingFaceLogout()
|
||||
if (!result.ok) {
|
||||
logger.error(`HF logout failed: ${result.error.message}`)
|
||||
return
|
||||
}
|
||||
setHfAuthStatus('not_authenticated')
|
||||
}, [])
|
||||
|
||||
if (!enabled) {
|
||||
return {
|
||||
hfAuthStatus: 'authenticated',
|
||||
hfAuthPolling: false,
|
||||
startHuggingFaceLogin: NOOP,
|
||||
handleHuggingFaceLogout: NOOP,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
hfAuthStatus,
|
||||
hfAuthPolling,
|
||||
startHuggingFaceLogin,
|
||||
handleHuggingFaceLogout,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user