ge / examples /index.html
4cko
/usr/local/rvm/gems/ruby-3.4.7/bin:/usr/local/rvm/gems/ruby-3.4.7@global/bin:/usr/local/rvm/rubies/ruby-3.4.7/bin:/home/codespace/.vscode-remote/data/User/globalStorage/github.copilot-chat/debugCommand:/home/codespace/.vscode-remote/data/User/globalStorage/github.copilot-chat/copilotCli:/vscode/bin/linux-x64/7e7950df89d055b5a378379db9ee14290772148a/bin/remote-cli:/home/codespace/.local/bin:/home/codespace/.dotnet:/home/codespace/nvm/current/bin:/home/codespace/.php/current/bin:/home/codespace/.python/current/bin:/home/codespace/java/current/bin:/home/codespace/.ruby/current/bin:/home/codespace/.local/bin:/usr/local/python/current/bin:/usr/local/py-utils/bin:/usr/local/jupyter:/usr/local/oryx:/usr/local/go/bin:/go/bin:/usr/local/sdkman/bin:/usr/local/sdkman/candidates/java/current/bin:/usr/local/sdkman/candidates/gradle/current/bin:/usr/local/sdkman/candidates/maven/current/bin:/usr/local/sdkman/candidates/ant/current/bin:/usr/local/rvm/gems/default/bin:/usr/local/rvm/gems/default@global/bin:/usr/local/rvm/rubies/default/bin:/usr/local/share/rbenv/bin:/usr/local/php/current/bin:/opt/conda/bin:/usr/local/nvs:/usr/local/share/nvm/versions/node/v24.14.0/bin:/usr/local/hugo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/share/dotnet:/home/codespace/.dotnet/tools:/usr/local/rvm/bin
a2c64e7
Raw
History Blame Contribute Delete
11.4 kB
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vico - Hugging Face Upload</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.container {
background: white;
border-radius: 10px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
max-width: 600px;
width: 100%;
padding: 40px;
}
h1 {
color: #333;
margin-bottom: 10px;
font-size: 28px;
}
.subtitle {
color: #666;
margin-bottom: 30px;
font-size: 14px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
color: #333;
font-weight: 600;
font-size: 14px;
}
input[type="text"],
input[type="password"],
textarea {
width: 100%;
padding: 12px;
border: 2px solid #e0e0e0;
border-radius: 5px;
font-size: 14px;
transition: border-color 0.3s;
font-family: 'Courier New', monospace;
}
input[type="text"]:focus,
input[type="password"]:focus,
textarea:focus {
outline: none;
border-color: #667eea;
}
input[type="file"] {
padding: 10px;
border: 2px dashed #667eea;
border-radius: 5px;
cursor: pointer;
}
.file-input-wrapper {
position: relative;
overflow: hidden;
}
button {
width: 100%;
padding: 12px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4);
}
button:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.loading {
display: none;
text-align: center;
margin: 20px 0;
}
.spinner {
border: 3px solid #f3f3f3;
border-top: 3px solid #667eea;
border-radius: 50%;
width: 30px;
height: 30px;
animation: spin 1s linear infinite;
margin: 0 auto 10px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.result {
display: none;
margin-top: 20px;
padding: 15px;
border-radius: 5px;
font-size: 14px;
}
.result.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.result.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.result-content {
margin-top: 10px;
background: rgba(255, 255, 255, 0.5);
padding: 10px;
border-radius: 3px;
overflow-x: auto;
font-family: 'Courier New', monospace;
font-size: 12px;
}
.file-info {
display: none;
background: #f5f5f5;
padding: 10px;
border-radius: 5px;
margin-bottom: 10px;
font-size: 13px;
color: #666;
}
.file-info.show {
display: block;
}
.helper-text {
font-size: 12px;
color: #999;
margin-top: 5px;
}
</style>
</head>
<body>
<div class="container">
<h1>🚀 Vico</h1>
<p class="subtitle">Upload file ke Hugging Face Dataset</p>
<form id="uploadForm">
<!-- Hugging Face Token -->
<div class="form-group">
<label for="token">Hugging Face Token *</label>
<input
type="password"
id="token"
placeholder="hf_xxxxxxxxxxxxxxxxxxxxxxx"
required
>
<p class="helper-text">
Dapatkan di: <a href="https://huggingface.co/settings/tokens" target="_blank">
huggingface.co/settings/tokens</a>
</p>
</div>
<!-- Repository ID -->
<div class="form-group">
<label for="repoId">Repository ID *</label>
<input
type="text"
id="repoId"
placeholder="username/dataset-name"
required
>
<p class="helper-text">Format: username/dataset-name (lowercase)</p>
</div>
<!-- Subfolder -->
<div class="form-group">
<label for="subfolder">Subfolder (Opsional)</label>
<input
type="text"
id="subfolder"
placeholder="data, datasets, dll"
>
<p class="helper-text">Biarkan kosong untuk upload ke root</p>
</div>
<!-- File Upload -->
<div class="form-group">
<label for="file">Pilih File *</label>
<div class="file-input-wrapper">
<input
type="file"
id="file"
required
>
</div>
<div id="fileInfo" class="file-info">
<span id="fileName"></span>
(<span id="fileSize"></span>)
</div>
</div>
<!-- Submit Button -->
<button type="submit" id="submitBtn">Upload File</button>
<!-- Loading State -->
<div class="loading" id="loading">
<div class="spinner"></div>
<p>Mengupload...</p>
</div>
<!-- Result Message -->
<div class="result" id="result">
<div id="resultContent"></div>
</div>
</form>
</div>
<script>
const API_URL = 'http://localhost:3000/api/upload';
// File input handler
document.getElementById('file').addEventListener('change', function(e) {
const file = e.target.files[0];
if (file) {
const fileInfo = document.getElementById('fileInfo');
document.getElementById('fileName').textContent = file.name;
document.getElementById('fileSize').textContent = formatFileSize(file.size);
fileInfo.classList.add('show');
}
});
// Format file size
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
}
// Form submit handler
document.getElementById('uploadForm').addEventListener('submit', async function(e) {
e.preventDefault();
const file = document.getElementById('file').files[0];
const token = document.getElementById('token').value;
const repoId = document.getElementById('repoId').value;
const subfolder = document.getElementById('subfolder').value;
if (!file || !token || !repoId) {
alert('Harap isi semua field yang diperlukan');
return;
}
// Show loading state
const submitBtn = document.getElementById('submitBtn');
const loading = document.getElementById('loading');
const result = document.getElementById('result');
submitBtn.disabled = true;
loading.style.display = 'block';
result.style.display = 'none';
try {
// Create FormData
const formData = new FormData();
formData.append('file', file);
formData.append('repo_id', repoId);
formData.append('token', token);
if (subfolder) {
formData.append('subfolder', subfolder);
}
// Upload
const response = await fetch(API_URL, {
method: 'POST',
body: formData
});
const data = await response.json();
// Show result
if (data.success) {
result.classList.remove('error');
result.classList.add('success');
result.innerHTML = `
<strong>✅ ${data.message}</strong>
<div class="result-content">
<strong>File:</strong> ${data.data.file_name}<br>
<strong>Size:</strong> ${formatFileSize(data.data.file_size)}<br>
<strong>Repo:</strong> ${data.data.repo_id}<br>
<strong>URL:</strong> <a href="${data.data.url}" target="_blank">${data.data.url}</a><br>
<strong>Time:</strong> ${new Date(data.data.upload_timestamp).toLocaleString('id-ID')}
</div>
`;
} else {
result.classList.remove('success');
result.classList.add('error');
result.innerHTML = `
<strong>❌ ${data.error}</strong>
<div class="result-content">${JSON.stringify(data, null, 2)}</div>
`;
}
result.style.display = 'block';
} catch (error) {
result.classList.remove('success');
result.classList.add('error');
result.innerHTML = `
<strong>❌ Error: ${error.message}</strong>
<div class="result-content">
Pastikan API server berjalan di ${API_URL}
</div>
`;
result.style.display = 'block';
} finally {
submitBtn.disabled = false;
loading.style.display = 'none';
}
});
</script>
</body>
</html>