22 * HuggingFace Provider Implementation
33 */
44
5- import { Errors , HF_SPACES } from '@z-image/shared'
5+ import { ApiError , ApiErrorCode , Errors , HF_SPACES } from '@z-image/shared'
66import { MAX_INT32 } from '../constants'
77import { callGradioApi } from '../utils'
88import type { ImageProvider , ProviderGenerateRequest , ProviderGenerateResult } from './types'
@@ -28,6 +28,26 @@ function parseSeedFromResponse(modelId: string, result: unknown[], fallbackSeed:
2828 return fallbackSeed
2929}
3030
31+ function getCandidateBaseUrls ( modelId : string ) : string [ ] {
32+ const primary = HF_SPACES [ modelId as keyof typeof HF_SPACES ] || HF_SPACES [ 'z-image-turbo' ]
33+ // Known mirror space for z-image-turbo. Helps when a space is cold/blocked/deleted.
34+ const fallbacks =
35+ modelId === 'z-image-turbo' ? [ 'https://luca115-z-image-turbo.hf.space' ] : ( [ ] as string [ ] )
36+ return [ primary , ...fallbacks ] . filter ( Boolean )
37+ }
38+
39+ function isNotFoundProviderError ( err : unknown ) : boolean {
40+ if ( err instanceof ApiError ) {
41+ return err . code === ApiErrorCode . PROVIDER_ERROR && ( err . details ?. upstream || '' ) . includes ( '404' )
42+ }
43+ if ( err && typeof err === 'object' && 'code' in err ) {
44+ const code = ( err as { code ?: unknown } ) . code
45+ const details = ( err as { details ?: unknown } ) . details as { upstream ?: string } | undefined
46+ return code === ApiErrorCode . PROVIDER_ERROR && ( details ?. upstream || '' ) . includes ( '404' )
47+ }
48+ return false
49+ }
50+
3151/** Model-specific Gradio configurations */
3252const MODEL_CONFIGS : Record <
3353 string ,
@@ -58,31 +78,50 @@ export class HuggingFaceProvider implements ImageProvider {
5878 async generate ( request : ProviderGenerateRequest ) : Promise < ProviderGenerateResult > {
5979 const seed = request . seed ?? Math . floor ( Math . random ( ) * MAX_INT32 )
6080 const modelId = request . model || 'z-image-turbo'
61- const baseUrl = HF_SPACES [ modelId as keyof typeof HF_SPACES ] || HF_SPACES [ 'z-image-turbo' ]
6281 const config = MODEL_CONFIGS [ modelId ] || MODEL_CONFIGS [ 'z-image-turbo' ]
6382
6483 // Debug: log model info (uncomment for debugging)
6584 // console.log(`[HuggingFace] Model: ${modelId}, BaseURL: ${baseUrl}`)
6685
67- const data = await callGradioApi (
68- baseUrl ,
69- config . endpoint ,
70- config . buildData ( request , seed ) ,
71- request . authToken
72- )
86+ let lastErr : unknown
87+ let imageUrl : string | undefined
88+ let data : unknown [ ] | undefined
89+
90+ for ( const baseUrl of getCandidateBaseUrls ( modelId ) ) {
91+ try {
92+ data = await callGradioApi (
93+ baseUrl ,
94+ config . endpoint ,
95+ config . buildData ( request , seed ) ,
96+ request . authToken
97+ )
98+
99+ const result = data as Array < { url ?: string } | number | string >
100+ const first = result [ 0 ]
101+ const rawUrl =
102+ typeof first === 'string' ? first : ( first as { url ?: string } | null | undefined ) ?. url
103+ imageUrl = rawUrl ? normalizeImageUrl ( baseUrl , rawUrl ) : undefined
104+ if ( ! imageUrl ) {
105+ // A successful call without an image payload is not a base-URL issue.
106+ throw Errors . generationFailed ( 'HuggingFace' , 'No image returned' )
107+ }
108+ break
109+ } catch ( err ) {
110+ lastErr = err
111+ // Try next base URL only for 404-type provider errors.
112+ if ( isNotFoundProviderError ( err ) ) continue
113+ throw err
114+ }
115+ }
73116
74- const result = data as Array < { url ?: string } | number | string >
75- const first = result [ 0 ]
76- const rawUrl =
77- typeof first === 'string' ? first : ( first as { url ?: string } | null | undefined ) ?. url
78- const imageUrl = rawUrl ? normalizeImageUrl ( baseUrl , rawUrl ) : undefined
79117 if ( ! imageUrl ) {
118+ if ( lastErr ) throw lastErr
80119 throw Errors . generationFailed ( 'HuggingFace' , 'No image returned' )
81120 }
82121
83122 return {
84123 url : imageUrl ,
85- seed : parseSeedFromResponse ( modelId , result , seed ) ,
124+ seed : parseSeedFromResponse ( modelId , data as unknown [ ] , seed ) ,
86125 }
87126 }
88127}
0 commit comments