Eji-Sensei14's picture
Upload folder using huggingface_hub
c6535db verified
/**
* Generates a RFC4122 compliant UUID v4 using the native crypto API when available
* @returns {string} A properly formatted UUID string
*/
export const generateUUID = () => {
// Use native crypto.randomUUID() if available (modern browsers)
if (
typeof crypto !== 'undefined' &&
typeof crypto.randomUUID === 'function'
) {
return crypto.randomUUID()
}
// Fallback implementation for older browsers
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (Math.random() * 16) | 0
const v = c === 'x' ? r : (r & 0x3) | 0x8
return v.toString(16)
})
}
const hasAnnotation = (filepath) =>
/\[(input|output|temp)\]/i.test(filepath)
const createAnnotation = (filepath, rootFolder = 'input') =>
!hasAnnotation(filepath) && rootFolder !== 'input' ? ` [${rootFolder}]` : ''
const createPath = (filename, subfolder = '') =>
subfolder ? `${subfolder}/${filename}` : filename
/** Creates annotated filepath in format used by folder_paths.py */
export function createAnnotatedPath(
item,
options = {}
) {
const { rootFolder = 'input', subfolder } = options
if (typeof item === 'string')
return `${createPath(item, subfolder)}${createAnnotation(item, rootFolder)}`
return `${createPath(item.filename ?? '', item.subfolder)}${
item.type ? createAnnotation(item.type, rootFolder) : ''
}`
}
/**
* Parses a filepath into its filename and subfolder components.
*
* @example
* parseFilePath('folder/file.txt') // → { filename: 'file.txt', subfolder: 'folder' }
* parseFilePath('/folder/file.txt') // → { filename: 'file.txt', subfolder: 'folder' }
* parseFilePath('file.txt') // → { filename: 'file.txt', subfolder: '' }
* parseFilePath('folder//file.txt') // → { filename: 'file.txt', subfolder: 'folder' }
*
* @param filepath The filepath to parse
* @returns Object containing filename and subfolder
*/
export function parseFilePath(filepath) {
if (!filepath?.trim()) return { filename: '', subfolder: '' }
const normalizedPath = filepath
.replace(/[\\/]+/g, '/') // Normalize path separators
.replace(/^\//, '') // Remove leading slash
.replace(/\/$/, '') // Remove trailing slash
const lastSlashIndex = normalizedPath.lastIndexOf('/')
if (lastSlashIndex === -1) {
return {
filename: normalizedPath,
subfolder: ''
}
}
return {
filename: normalizedPath.slice(lastSlashIndex + 1),
subfolder: normalizedPath.slice(0, lastSlashIndex)
}
}
export function useValueTransform(
transform,
initialValue
) {
let internalValue = initialValue
let cachedValue = transform(initialValue)
let isChanged = false
return {
get: () => {
if (!isChanged) return cachedValue
cachedValue = transform(internalValue)
return cachedValue
},
set: (value) => {
isChanged = true
internalValue = value
}
}
}
export function isBase64(str) {
// 移除可能的Data URL前缀
const base64String = str.replace(/^data:image\/\w+;base64,/, '');
// Base64正则表达式
const base64Regex = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$/;
// 检查长度是否为4的倍数且符合Base64字符集
return base64String.length % 4 === 0 && base64Regex.test(base64String);
}
export const isURL = str => {
if (!str) return false;
return str.startsWith('http://') || str.startsWith('https://');
}