|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<style> |
|
body { |
|
font-family: Arial, sans-serif; |
|
} |
|
input, button, progress { |
|
display: block; |
|
margin-top: 10px; |
|
} |
|
#message { |
|
margin-top: 20px; |
|
color: blue; |
|
} |
|
#error { |
|
color: red; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<label for="tokenInput">Hugging Face Token:</label> |
|
<input type="password" id="tokenInput" name="tokenInput"> |
|
<label for="repoInput">Repository ID:</label> |
|
<input type="text" id="repoInput" name="repoInput" placeholder="my-user/nlp-model"> |
|
<input type="file" id="fileUpload" multiple> |
|
<button id="uploadButton">Upload Files</button> |
|
<div id="processingMessage"></div> |
|
<progress id="progressBar" value="0" max="100"></progress> |
|
<div id="message"></div> |
|
<div id="error"></div> |
|
|
|
<script type="module"> |
|
import { createRepo, uploadFiles } from "https://cdn.jsdelivr.net/npm/@huggingface/hub@0.8.3/+esm"; |
|
|
|
class FileUploader { |
|
constructor() { |
|
this.fileInput = document.getElementById('fileUpload'); |
|
this.uploadButton = document.getElementById('uploadButton'); |
|
this.tokenInput = document.getElementById('tokenInput'); |
|
this.repoInput = document.getElementById('repoInput'); |
|
this.progressBar = document.getElementById('progressBar'); |
|
this.messageDiv = document.getElementById('message'); |
|
this.errorDiv = document.getElementById('error'); |
|
this.processingMessage = document.getElementById('processingMessage'); |
|
|
|
this.hijackFetch(); |
|
this.uploadButton.addEventListener('click', this.upload); |
|
} |
|
|
|
hijackFetch = () => { |
|
const originalFetch = fetch; |
|
this.totalUploaded = 0; |
|
this.progressMap = new Map(); |
|
|
|
fetch = (url, init) => init.method !== 'PUT' ? originalFetch(url, init) : this.handleFetch(url, init); |
|
}; |
|
|
|
handleFetch = (url, init) => new Promise((resolve, reject) => { |
|
const xhr = new XMLHttpRequest(); |
|
xhr.open(init.method, url); |
|
for (let header in init.headers) xhr.setRequestHeader(header, init.headers[header]); |
|
xhr.onload = () => resolve({ok: xhr.status >= 200 && xhr.status < 300, status: xhr.status, statusText: xhr.statusText, text: () => Promise.resolve(xhr.responseText), json: () => Promise.resolve(JSON.parse(xhr.responseText)), headers: {get: (header) => xhr.getResponseHeader(header)}}); |
|
xhr.onerror = () => reject(new TypeError('Network request failed')); |
|
xhr.ontimeout = () => reject(new TypeError('Network request failed due to timeout')); |
|
xhr.upload.onprogress = (event) => this.updateUploadProgress(event, url); |
|
xhr.send(init.body); |
|
}); |
|
|
|
updateUploadProgress = (event, url) => { |
|
if (event.lengthComputable) { |
|
this.progressMap.set(url, event.loaded); |
|
this.totalUploaded = Array.from(this.progressMap.values()).reduce((a, b) => a + b, 0); |
|
this.progressBar.value = this.totalUploaded; |
|
this.processingMessage.textContent = this.totalUploaded === 0 ? 'Preparing your upload' : this.totalUploaded === this.progressBar.max ? 'Processing your upload' : ''; |
|
} |
|
}; |
|
|
|
upload = async () => { |
|
const files = Array.from(this.fileInput.files); |
|
const HF_ACCESS_TOKEN = this.tokenInput.value; |
|
const REPO_ID = this.repoInput.value; |
|
this.progressBar.value = 0; |
|
this.messageDiv.textContent = ''; |
|
this.errorDiv.textContent = ''; |
|
this.processingMessage.textContent = ''; |
|
|
|
if (files.length > 0) { |
|
this.progressBar.max = files.reduce((total, file) => total + file.size, 0); |
|
this.totalUploaded = 0; |
|
this.startTime = Date.now(); |
|
|
|
try { |
|
await this.createRepository(REPO_ID, HF_ACCESS_TOKEN); |
|
await this.uploadFilesToRepo(REPO_ID, HF_ACCESS_TOKEN, files); |
|
this.handleUploadSuccess(files); |
|
} catch (error) { |
|
this.handleErrorDuringUpload(error); |
|
} |
|
} else { |
|
this.messageDiv.textContent = 'Please select files to upload'; |
|
} |
|
}; |
|
|
|
createRepository = async (REPO_ID, HF_ACCESS_TOKEN) => { |
|
try { |
|
await createRepo({repo: REPO_ID, credentials: { accessToken: HF_ACCESS_TOKEN }}); |
|
} catch (error) { |
|
if (error.message !== 'You already created this model repo') throw error; |
|
} |
|
}; |
|
|
|
uploadFilesToRepo = (REPO_ID, HF_ACCESS_TOKEN, files) => uploadFiles({repo: REPO_ID, credentials: { accessToken: HF_ACCESS_TOKEN }, files: files.map(file => ({path: file.name, content: file}))}); |
|
|
|
handleUploadSuccess = (files) => { |
|
const elapsedTime = (Date.now() - this.startTime) / 1000; |
|
let totalSizeMB = this.progressBar.max / (1024 * 1024) |
|
let speed = totalSizeMB / elapsedTime; |
|
this.messageDiv.innerHTML = `All files uploaded successfully in ${elapsedTime.toFixed(2)} seconds, for all ${totalSizeMB.toFixed(2)} MB in the ${files.length} files, speed ${speed.toFixed(2)} MB/s.`; |
|
this.processingMessage.textContent = "All files processed"; |
|
}; |
|
|
|
handleErrorDuringUpload = (error) => { |
|
console.error('Error during upload', error); |
|
this.errorDiv.textContent = 'Error during upload: ' + error.message; |
|
}; |
|
} |
|
|
|
new FileUploader(); |
|
</script> |
|
</body> |
|
</html> |
|
|