/** * Parse Hugging Face URL and extract username/organization * @param {string} url - The Hugging Face URL * @returns {object} - Parsed data with type and username */ export function parseHuggingFaceUrl(url) { try { // Remove trailing slash if present url = url.trim().replace(/\/$/, ''); // Handle different URL formats let parsedUrl; if (url.startsWith('http://') || url.startsWith('https://')) { parsedUrl = new URL(url); } else if (url.startsWith('huggingface.co')) { parsedUrl = new URL(`https://${url}`); } else { // Assume it's just a username return { type: 'profile', username: url, profileUrl: `https://huggingface.co/${url}`, resourceType: null, resourceName: null, fullUrl: `https://huggingface.co/${url}` }; } // Check if it's a Hugging Face domain 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'); } // Extract username/org from different URL types let username = pathParts[0]; let resourceType = null; let resourceName = null; let type = 'profile'; // Detect resource type and name if (pathParts.length >= 2) { // Check for direct resource URLs like /username/model-name const secondPart = pathParts[1]; // Check if it's a resource collection page if (secondPart === 'models' || secondPart === 'datasets' || secondPart === 'spaces') { // This is a collection page, not a specific resource type = 'profile'; resourceType = null; resourceName = null; } else { // This might be a direct resource URL // Models, datasets, and spaces have direct URLs like /username/resource-name // We need to detect what type based on context or default to model resourceName = secondPart; // Try to detect resource type from URL structure if (parsedUrl.hostname === 'huggingface.co') { // Check for spaces subdomain or path hints if (pathParts.length >= 3) { if (pathParts[2] === 'tree' || pathParts[2] === 'blob' || pathParts[2] === 'resolve') { resourceType = 'model'; // Repository-like structure usually means model } else if (pathParts[2] === 'discussions' || pathParts[2] === 'settings') { resourceType = 'model'; // These are common in model repos } } else { // Default to model for direct /username/name pattern resourceType = 'model'; } } } } else if (parsedUrl.hostname.includes('.hf.space')) { // This is a Spaces URL like username-spacename.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'; } } // Check for datasets in path 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]; // Correct the username resourceType = 'dataset'; resourceName = datasetParts[1]; } } // Check for spaces in path 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]; // Correct the username resourceType = 'space'; resourceName = spaceParts[1]; } } return { type, username, profileUrl: `https://huggingface.co/${username}`, resourceType, resourceName, fullUrl: parsedUrl.href }; } catch (error) { throw new Error(`Invalid Hugging Face URL: ${error.message}`); } } /** * Get the avatar URL for a Hugging Face user/organization * @param {string} username - The username or organization name * @returns {string} - The avatar URL */ export function getAvatarUrl(username) { // Hugging Face avatar URL pattern return `https://huggingface.co/avatars/${username}.svg`; }