audio_to_text / script.js
missvector's picture
Upd
51c858c
// ============================================
// AUDIO TO TEXT - ЧИСТЫЙ СТАТИК
// ============================================
const API_URL = 'https://api-inference.huggingface.co/models/openai/whisper-tiny';
// Элементы интерфейса
const copyBtn = document.getElementById('copyBtn');
const copyFeedback = document.getElementById('copyFeedback');
const transcriptText = document.getElementById('transcriptText');
const dropZone = document.getElementById('dropZone');
const attachBtn = document.getElementById('attachBtn');
const transcriptArea = document.getElementById('transcriptArea');
// ========== УПРАВЛЕНИЕ ТОКЕНОМ ==========
let HF_TOKEN = localStorage.getItem('hf_token');
function promptForToken() {
const token = prompt('🔑 Введи свой Hugging Face токен:\n(получить: https://huggingface.co/settings/tokens)');
if (token) {
localStorage.setItem('hf_token', token);
HF_TOKEN = token;
return true;
}
return false;
}
function resetToken() {
localStorage.removeItem('hf_token');
HF_TOKEN = null;
alert('🔄 Токен сброшен. Обнови страницу для ввода нового.');
}
// Проверяем токен при загрузке
if (!HF_TOKEN) {
promptForToken();
}
// ========== КОПИРОВАНИЕ ==========
copyBtn.addEventListener('click', async () => {
if (transcriptText.value) {
await navigator.clipboard.writeText(transcriptText.value);
copyFeedback.classList.add('show');
setTimeout(() => copyFeedback.classList.remove('show'), 2000);
}
});
// ========== DRAG & DROP ==========
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
dropZone.addEventListener(eventName, () => {
dropZone.classList.add('drag-over');
});
});
['dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, () => {
dropZone.classList.remove('drag-over');
});
});
dropZone.addEventListener('drop', (e) => {
const files = e.dataTransfer.files;
if (files.length) {
handleFile(files[0]);
}
});
// ========== ВЫБОР ФАЙЛА ==========
attachBtn.addEventListener('click', () => {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'audio/*';
input.onchange = (e) => {
if (e.target.files.length) {
handleFile(e.target.files[0]);
}
};
input.click();
});
dropZone.addEventListener('click', (e) => {
if (e.target !== attachBtn && !attachBtn.contains(e.target)) {
attachBtn.click();
}
});
// ========== ОСНОВНАЯ ФУНКЦИЯ ==========
async function handleFile(file) {
console.log('🎵 файл:', file.name);
// Проверяем токен
if (!HF_TOKEN) {
if (!promptForToken()) {
transcriptText.value = '❌ Без токена невозможно распознать речь';
return;
}
}
dropZone.style.display = 'none';
transcriptArea.classList.add('active');
transcriptText.value = '🔄 Отправка на распознавание...';
const formData = new FormData();
formData.append('file', file);
try {
const arrayBuffer = await file.arrayBuffer();
const response = await fetch(API_URL, {
method: 'POST',
headers: {
'Authorization': `Bearer ${HF_TOKEN}`,
'Content-Type': file.type || 'audio/mpeg'
},
body: arrayBuffer
});
// Обработка ошибок авторизации
if (response.status === 401 || response.status === 403) {
localStorage.removeItem('hf_token');
HF_TOKEN = null;
transcriptText.value = '❌ Токен недействителен. Обнови страницу и введи новый.';
return;
}
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
transcriptText.value = data.text || '⚠️ Пустой ответ от API';
} catch (error) {
transcriptText.value = `❌ Ошибка: ${error.message}`;
console.error(error);
}
}
// ========== ДОБАВЛЯЕМ КНОПКУ СБРОСА В ФУТЕР ==========
// Этот код добавит ссылку для сброса токена в футер
document.addEventListener('DOMContentLoaded', () => {
const footer = document.querySelector('.footer');
if (footer) {
const resetLink = document.createElement('span');
resetLink.innerHTML = ' · <a href="#" onclick="resetToken(); return false;">🔄 сбросить токен</a>';
footer.appendChild(resetLink);
}
});
// Делаем функцию глобальной
window.resetToken = resetToken;