diff --git a/css/styles.css b/css/styles.css
index dff0085..80e516a 100644
--- a/css/styles.css
+++ b/css/styles.css
@@ -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;
+}
diff --git a/index.html b/index.html
index 97aa3b4..479b645 100644
--- a/index.html
+++ b/index.html
@@ -90,6 +90,14 @@
!
+
+
+
+
+
+
+
+
diff --git a/js/app.js b/js/app.js
index 05d55ff..b40ee9d 100644
--- a/js/app.js
+++ b/js/app.js
@@ -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;