Add HuggingFace model auto-fetch feature

- Added model identifier input field with Fetch button
- Added loading indicator for fetch operation
- Added async handleHfFetch function to fetch config from HuggingFace
- Fetches config from https://huggingface.co/{model}/blob/main/config.json
- Replaces current config when fetch is successful
- Shows 'Model not found' error for 404 responses
- Sets focus on model input after successful fetch
- Added translations for new fields
This commit is contained in:
Arseniy Romenskiy 2026-04-12 01:52:34 +03:00
parent 2a1522fa70
commit fb2d114d38
3 changed files with 97 additions and 0 deletions

View file

@ -367,3 +367,18 @@ html[lang="en"] .tooltip-icon:hover::after {
align-self: flex-end;
}
}
.loading-indicator {
text-align: center;
font-style: italic;
color: #0000FF;
padding: 10px;
}
#hf-fetch-btn {
background-color: #0000FF;
}
#hf-fetch-btn:hover {
background-color: #0000AA;
}

View file

@ -90,6 +90,14 @@
<span class="tooltip-icon" data-tooltip-ru="Загрузите config.json из модели. Автоматически заполнит поля и запустит расчет" data-tooltip-en="Upload model config.json. Auto-fills fields and runs calculation"></span>
<span class="error-icon" style="display:none; color: #FF0000; cursor: help; margin-left: 5px;">!</span>
<div class="form-group" style="display: flex; align-items: center; gap: 10px;">
<label for="hf-model" data-key="hf_model_label" style="margin-bottom: 0; white-space: nowrap;">Model (HuggingFace)</label>
<input type="text" id="hf-model" placeholder="" style="flex: 1;">
<button type="button" id="hf-fetch-btn" data-key="hf_fetch_btn" style="margin-bottom: 0;">Fetch</button>
</div>
<div id="loading-indicator" style="text-align: center; font-style: italic; color: #0000FF; padding: 10px; display: none;"></div>
<div class="checkbox-group">
<input type="checkbox" id="asymmetric">
<label for="asymmetric" data-key="asymmetric_label">Асимметричный Контекст</label>

View file

@ -72,6 +72,10 @@
config_file_label: 'Config.json',
config_file_ru: 'Загрузите config.json из модели. Автоматически заполнит поля и запустит расчет',
config_file_en: 'Upload model config.json. Auto-fills fields and runs calculation',
hf_model_label: 'Model (HuggingFace)',
hf_model_ru: 'Введите имя модели',
hf_model_en: 'Please enter a model name',
hf_fetch_btn: 'Fetch',
example_text: 'Example: context=8192, layers=32, kv_heads=32, head_size=128, model_size=7 GB, parallel=1',
results_title: 'Results',
k_cache: 'K cache:',
@ -187,6 +191,9 @@
const configFileInput = document.getElementById('config-file');
const resetBtn = document.getElementById('reset-btn');
const modelNameDisplay = document.getElementById('model-name-display');
const hfModelInput = document.getElementById('hf-model');
const hfFetchBtn = document.getElementById('hf-fetch-btn');
const loadingIndicator = document.getElementById('loading-indicator');
// Initialize
function init() {
@ -216,6 +223,11 @@
if (resetBtn) {
resetBtn.addEventListener('click', handleReset);
}
// HF fetch button
if (hfFetchBtn) {
hfFetchBtn.addEventListener('click', handleHfFetch);
}
}
// Toggle language
@ -270,6 +282,12 @@
configTooltip.setAttribute('data-tooltip-en', translations[currentLang].config_file_en);
}
// Update HF model field translation
const hfModelLabel = document.querySelector('#hf-model + label');
if (hfModelLabel) {
hfModelLabel.textContent = translations[currentLang].hf_model_label;
}
// Re-evaluate errors
if (window.configErrors && Object.keys(window.configErrors).length > 0) {
showConfigErrors();
@ -520,6 +538,7 @@
document.getElementById('model-size').value = '';
document.getElementById('parallel').value = '1';
document.getElementById('full-attention').value = '';
hfModelInput.value = '';
// Reset quantization
document.getElementById('k-type').value = 'KV';
@ -535,6 +554,61 @@
clearAllTooltips();
}
// HuggingFace fetch function
async function handleHfFetch() {
const modelName = hfModelInput.value.trim();
if (!modelName) {
showConfigError('hf-model', currentLang === 'ru'
? 'Введите имя модели'
: 'Please enter a model name');
return;
}
// Show loading state
loadingIndicator.textContent = currentLang === 'ru'
? 'Загрузка config из HuggingFace...'
: 'Fetching config from HuggingFace...';
loadingIndicator.style.display = 'block';
const url = `https://huggingface.co/${modelName}/blob/main/config.json`;
try {
const response = await fetch(url);
if (!response.ok) {
if (response.status === 404) {
showConfigError('hf-model', currentLang === 'ru'
? 'Модель не найдена'
: 'Model not found');
} else {
showConfigError('hf-model', currentLang === 'ru'
? `Ошибка загрузки: ${response.status}`
: `Error loading: ${response.status}`);
}
loadingIndicator.style.display = 'none';
return;
}
const config = await response.json();
// Clear errors
window.configErrors = {};
clearAllTooltips();
// Populate from config
populateFromConfig(config);
// Hide loading and set focus
loadingIndicator.style.display = 'none';
hfModelInput.focus();
} catch (err) {
loadingIndicator.style.display = 'none';
showConfigError('hf-model', currentLang === 'ru'
? `Не удалось загрузить config: ${err.message}`
: `Failed to load config: ${err.message}`);
}
}
// Show config error
function showConfigError(field, message) {
window.configErrors[field] = message;