|
import { |
|
RUNTIME_URL, |
|
SLEEPTIME_URL, |
|
SPACE_STATUS_ERROR_MSG |
|
} from "../constants"; |
|
import type { SpaceStatusCallback } from "../types"; |
|
|
|
export async function check_space_status( |
|
id: string, |
|
type: "subdomain" | "space_name", |
|
status_callback: SpaceStatusCallback |
|
): Promise<void> { |
|
let endpoint = |
|
type === "subdomain" |
|
? `https://huggingface.co/api/spaces/by-subdomain/${id}` |
|
: `https://huggingface.co/api/spaces/${id}`; |
|
let response; |
|
let _status; |
|
try { |
|
response = await fetch(endpoint); |
|
_status = response.status; |
|
if (_status !== 200) { |
|
throw new Error(); |
|
} |
|
response = await response.json(); |
|
} catch (e) { |
|
status_callback({ |
|
status: "error", |
|
load_status: "error", |
|
message: SPACE_STATUS_ERROR_MSG, |
|
detail: "NOT_FOUND" |
|
}); |
|
return; |
|
} |
|
|
|
if (!response || _status !== 200) return; |
|
const { |
|
runtime: { stage }, |
|
id: space_name |
|
} = response; |
|
|
|
switch (stage) { |
|
case "STOPPED": |
|
case "SLEEPING": |
|
status_callback({ |
|
status: "sleeping", |
|
load_status: "pending", |
|
message: "Space is asleep. Waking it up...", |
|
detail: stage |
|
}); |
|
|
|
setTimeout(() => { |
|
check_space_status(id, type, status_callback); |
|
}, 1000); |
|
break; |
|
case "PAUSED": |
|
status_callback({ |
|
status: "paused", |
|
load_status: "error", |
|
message: |
|
"This space has been paused by the author. If you would like to try this demo, consider duplicating the space.", |
|
detail: stage, |
|
discussions_enabled: await discussions_enabled(space_name) |
|
}); |
|
break; |
|
case "RUNNING": |
|
case "RUNNING_BUILDING": |
|
status_callback({ |
|
status: "running", |
|
load_status: "complete", |
|
message: "", |
|
detail: stage |
|
}); |
|
break; |
|
case "BUILDING": |
|
status_callback({ |
|
status: "building", |
|
load_status: "pending", |
|
message: "Space is building...", |
|
detail: stage |
|
}); |
|
|
|
setTimeout(() => { |
|
check_space_status(id, type, status_callback); |
|
}, 1000); |
|
break; |
|
default: |
|
status_callback({ |
|
status: "space_error", |
|
load_status: "error", |
|
message: "This space is experiencing an issue.", |
|
detail: stage, |
|
discussions_enabled: await discussions_enabled(space_name) |
|
}); |
|
break; |
|
} |
|
} |
|
|
|
const RE_DISABLED_DISCUSSION = |
|
/^(?=[^]*\b[dD]iscussions{0,1}\b)(?=[^]*\b[dD]isabled\b)[^]*$/; |
|
export async function discussions_enabled(space_id: string): Promise<boolean> { |
|
try { |
|
const r = await fetch( |
|
`https://huggingface.co/api/spaces/${space_id}/discussions`, |
|
{ |
|
method: "HEAD" |
|
} |
|
); |
|
const error = r.headers.get("x-error-message"); |
|
|
|
if (error && RE_DISABLED_DISCUSSION.test(error)) return false; |
|
return true; |
|
} catch (e) { |
|
return false; |
|
} |
|
} |
|
|
|
export async function get_space_hardware( |
|
space_id: string, |
|
hf_token?: `hf_${string}` | undefined |
|
): Promise<(typeof hardware_types)[number]> { |
|
const headers: { Authorization?: string } = {}; |
|
if (hf_token) { |
|
headers.Authorization = `Bearer ${hf_token}`; |
|
} |
|
|
|
try { |
|
const res = await fetch( |
|
`https://huggingface.co/api/spaces/${space_id}/${RUNTIME_URL}`, |
|
{ headers } |
|
); |
|
|
|
if (res.status !== 200) |
|
throw new Error("Space hardware could not be obtained."); |
|
|
|
const { hardware } = await res.json(); |
|
|
|
return hardware.current; |
|
} catch (e: any) { |
|
throw new Error(e.message); |
|
} |
|
} |
|
|
|
export async function set_space_timeout( |
|
space_id: string, |
|
timeout: number, |
|
hf_token?: `hf_${string}` |
|
): Promise<any> { |
|
const headers: { Authorization?: string } = {}; |
|
if (hf_token) { |
|
headers.Authorization = `Bearer ${hf_token}`; |
|
} |
|
|
|
const body: { |
|
seconds?: number; |
|
} = { |
|
seconds: timeout |
|
}; |
|
|
|
try { |
|
const res = await fetch( |
|
`https://huggingface.co/api/spaces/${space_id}/${SLEEPTIME_URL}`, |
|
{ |
|
method: "POST", |
|
headers: { "Content-Type": "application/json", ...headers }, |
|
body: JSON.stringify(body) |
|
} |
|
); |
|
|
|
if (res.status !== 200) { |
|
throw new Error( |
|
"Could not set sleep timeout on duplicated Space. Please visit *ADD HF LINK TO SETTINGS* to set a timeout manually to reduce billing charges." |
|
); |
|
} |
|
|
|
const response = await res.json(); |
|
return response; |
|
} catch (e: any) { |
|
throw new Error(e.message); |
|
} |
|
} |
|
|
|
export const hardware_types = [ |
|
"cpu-basic", |
|
"cpu-upgrade", |
|
"cpu-xl", |
|
"t4-small", |
|
"t4-medium", |
|
"a10g-small", |
|
"a10g-large", |
|
"a10g-largex2", |
|
"a10g-largex4", |
|
"a100-large", |
|
"zero-a10g", |
|
"h100", |
|
"h100x8" |
|
] as const; |
|
|