|
|
interface ParsedHuggingFaceUrl { |
|
|
type: string; |
|
|
username: string; |
|
|
profileUrl: string; |
|
|
resourceType: string | null; |
|
|
resourceName: string | null; |
|
|
fullUrl: string; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function parseHuggingFaceUrl(url: string): ParsedHuggingFaceUrl { |
|
|
try { |
|
|
|
|
|
url = url.trim().replace(/\/$/, ''); |
|
|
|
|
|
|
|
|
let parsedUrl: URL; |
|
|
if (url.startsWith('http://') || url.startsWith('https://')) { |
|
|
parsedUrl = new URL(url); |
|
|
} else if (url.startsWith('huggingface.co')) { |
|
|
parsedUrl = new URL(`https://${url}`); |
|
|
} else { |
|
|
|
|
|
return { |
|
|
type: 'profile', |
|
|
username: url, |
|
|
profileUrl: `https://huggingface.co/${url}`, |
|
|
resourceType: null, |
|
|
resourceName: null, |
|
|
fullUrl: `https://huggingface.co/${url}` |
|
|
}; |
|
|
} |
|
|
|
|
|
|
|
|
if (!parsedUrl.hostname.includes('huggingface.co')) { |
|
|
throw new Error('Not a valid Hugging Face URL'); |
|
|
} |
|
|
|
|
|
const pathParts = parsedUrl.pathname.split('/').filter(part => part); |
|
|
|
|
|
if (pathParts.length === 0) { |
|
|
throw new Error('No username or organization found in URL'); |
|
|
} |
|
|
|
|
|
|
|
|
let username = pathParts[0]; |
|
|
let resourceType: string | null = null; |
|
|
let resourceName: string | null = null; |
|
|
let type = 'profile'; |
|
|
|
|
|
|
|
|
if (pathParts.length >= 2) { |
|
|
|
|
|
const secondPart = pathParts[1]; |
|
|
|
|
|
|
|
|
if (secondPart === 'models' || secondPart === 'datasets' || secondPart === 'spaces') { |
|
|
|
|
|
type = 'profile'; |
|
|
resourceType = null; |
|
|
resourceName = null; |
|
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
resourceName = secondPart; |
|
|
|
|
|
|
|
|
if (parsedUrl.hostname === 'huggingface.co') { |
|
|
|
|
|
if (pathParts.length >= 3) { |
|
|
if (pathParts[2] === 'tree' || pathParts[2] === 'blob' || pathParts[2] === 'resolve') { |
|
|
resourceType = 'model'; |
|
|
} else if (pathParts[2] === 'discussions' || pathParts[2] === 'settings') { |
|
|
resourceType = 'model'; |
|
|
} |
|
|
} else { |
|
|
|
|
|
resourceType = 'model'; |
|
|
} |
|
|
} |
|
|
} |
|
|
} else if (parsedUrl.hostname.includes('.hf.space')) { |
|
|
|
|
|
const subdomain = parsedUrl.hostname.split('.')[0]; |
|
|
if (subdomain.includes('-')) { |
|
|
const parts = subdomain.split('-'); |
|
|
username = parts[0]; |
|
|
resourceName = parts.slice(1).join('-'); |
|
|
resourceType = 'space'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (parsedUrl.pathname.includes('/datasets/')) { |
|
|
const datasetPath = parsedUrl.pathname.split('/datasets/')[1]; |
|
|
const datasetParts = datasetPath.split('/').filter(p => p); |
|
|
if (datasetParts.length >= 2) { |
|
|
username = datasetParts[0]; |
|
|
resourceType = 'dataset'; |
|
|
resourceName = datasetParts[1]; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (parsedUrl.pathname.includes('/spaces/')) { |
|
|
const spacePath = parsedUrl.pathname.split('/spaces/')[1]; |
|
|
const spaceParts = spacePath.split('/').filter(p => p); |
|
|
if (spaceParts.length >= 2) { |
|
|
username = spaceParts[0]; |
|
|
resourceType = 'space'; |
|
|
resourceName = spaceParts[1]; |
|
|
} |
|
|
} |
|
|
|
|
|
return { |
|
|
type, |
|
|
username, |
|
|
profileUrl: `https://huggingface.co/${username}`, |
|
|
resourceType, |
|
|
resourceName, |
|
|
fullUrl: parsedUrl.href |
|
|
}; |
|
|
} catch (error: any) { |
|
|
throw new Error(`Invalid Hugging Face URL: ${error.message}`); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function getAvatarUrl(username: string): string { |
|
|
|
|
|
return `https://huggingface.co/avatars/${username}.svg`; |
|
|
} |