DocImageAI-Explorer / script.js
SamiKLN's picture
Upload 2 files
5e90e1e verified
// Configuration Axios
axios.defaults.baseURL = window.location.origin.includes('hf.space')
? window.location.origin
: 'http://localhost:8000';
console.log("API base URL:", axios.defaults.baseURL);
// Variables globales
let uploadedFiles = [];
const MAX_FILE_SIZE_MB = 50;
const SUPPORTED_TYPES = ['pdf', 'docx', 'pptx', 'xlsx', 'jpg', 'jpeg', 'png'];
// Éléments DOM
const elements = {
fileInput: document.getElementById('fileInput'),
dropArea: document.getElementById('dropArea'),
fileList: document.getElementById('fileList'),
uploadStatus: document.getElementById('uploadStatus'),
summaryFile: document.getElementById('summaryFile'),
captionFile: document.getElementById('captionFile'),
qaFile: document.getElementById('qaFile'),
summarizeBtn: document.getElementById('summarizeBtn'),
captionBtn: document.getElementById('captionBtn'),
askBtn: document.getElementById('askBtn'),
questionInput: document.getElementById('questionInput'),
summaryResult: document.getElementById('summaryResult'),
captionResult: document.getElementById('captionResult'),
answerResult: document.getElementById('answerResult'),
imagePreview: document.getElementById('imagePreview'),
summarySpinner: document.getElementById('summarySpinner'),
captionSpinner: document.getElementById('captionSpinner'),
qaSpinner: document.getElementById('qaSpinner')
};
// Initialisation
document.addEventListener('DOMContentLoaded', () => {
initVideoBackground();
setupEventListeners();
updateFileSelectors();
});
function initVideoBackground() {
const video = document.getElementById('bg-video');
if (video) {
try {
video.playbackRate = 0.8;
video.muted = true;
video.playsInline = true;
video.play().catch(e => console.log("Video play error:", e));
} catch (e) {
console.log("Video initialization error:", e);
}
video.onerror = () => {
document.body.style.background = "linear-gradient(135deg, #4a6fa5 0%, #166088 100%)";
};
}
}
function setupEventListeners() {
// Gestion de l'upload
if (elements.dropArea) {
elements.dropArea.addEventListener('click', () => elements.fileInput.click());
elements.dropArea.addEventListener('dragover', handleDragOver);
elements.dropArea.addEventListener('dragleave', handleDragLeave);
elements.dropArea.addEventListener('drop', handleDrop);
}
elements.fileInput.addEventListener('change', handleFileSelect);
// Boutons d'action
if (elements.summarizeBtn) {
elements.summarizeBtn.addEventListener('click', summarizeDocument);
}
if (elements.captionBtn) {
elements.captionBtn.addEventListener('click', generateCaption);
}
if (elements.askBtn) {
elements.askBtn.addEventListener('click', answerQuestion);
}
}
// Gestion des fichiers
function handleDragOver(e) {
e.preventDefault();
elements.dropArea.style.borderColor = '#4a6fa5';
elements.dropArea.style.backgroundColor = 'rgba(74, 111, 165, 0.1)';
}
function handleDragLeave() {
elements.dropArea.style.borderColor = '#4a6fa5';
elements.dropArea.style.backgroundColor = 'rgba(74, 111, 165, 0.05)';
}
function handleDrop(e) {
e.preventDefault();
handleDragLeave();
if (e.dataTransfer.files.length) {
elements.fileInput.files = e.dataTransfer.files;
handleFiles(elements.fileInput.files);
}
}
function handleFileSelect() {
if (elements.fileInput.files.length) {
handleFiles(elements.fileInput.files);
}
}
async function handleFiles(files) {
const validFiles = Array.from(files).filter(file => {
const ext = file.name.split('.').pop().toLowerCase();
const isValidType = SUPPORTED_TYPES.includes(ext);
const isValidSize = file.size <= MAX_FILE_SIZE_MB * 1024 * 1024;
if (!isValidType) {
showError(elements.uploadStatus, `Type non supporté: ${file.name}`);
return false;
}
if (!isValidSize) {
showError(elements.uploadStatus, `Fichier trop volumineux (max ${MAX_FILE_SIZE_MB}MB): ${file.name}`);
return false;
}
return true;
});
if (!validFiles.length) return;
showLoading(elements.uploadStatus, `Upload de ${validFiles.length} fichier(s)...`);
const formData = new FormData();
validFiles.forEach(file => formData.append('files', file));
try {
const response = await axios.post('/api/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
timeout: 60000
});
uploadedFiles = [...uploadedFiles, ...response.data];
updateFileSelectors();
renderFileList();
showSuccess(elements.uploadStatus, `${validFiles.length} fichier(s) uploadé(s) avec succès !`);
} catch (error) {
handleUploadError(error);
} finally {
elements.fileInput.value = '';
}
}
function renderFileList() {
if (!elements.fileList) return;
if (uploadedFiles.length === 0) {
elements.fileList.innerHTML = '<p class="empty-message">Aucun fichier uploadé</p>';
return;
}
elements.fileList.innerHTML = uploadedFiles.map(file => `
<div class="file-item" data-file-id="${file.file_id}">
<div class="file-info">
<span class="file-icon">${getFileIcon(file.file_type)}</span>
<span class="file-name">${file.file_name}</span>
<span class="file-type">${file.file_type.toUpperCase()}</span>
</div>
</div>
`).join('');
}
function updateFileSelectors() {
const selectors = [
{ element: elements.summaryFile, types: ['pdf', 'docx', 'pptx', 'xlsx'] },
{ element: elements.captionFile, types: ['jpg', 'jpeg', 'png'] },
{ element: elements.qaFile, types: ['pdf', 'docx', 'pptx', 'xlsx', 'jpg', 'jpeg', 'png'] }
];
selectors.forEach(({ element, types }) => {
if (!element) return;
const currentValue = element.value;
element.innerHTML = element.id === 'qaFile'
? '<option value="">-- Aucun --</option>'
: `<option value="">-- Choisir ${element.id.includes('summary') ? 'un document' : 'une image'} --</option>`;
uploadedFiles
.filter(file => types.includes(file.file_type.toLowerCase()))
.forEach(file => {
const option = new Option(
`${file.file_name} (${file.file_type.toUpperCase()})`,
file.file_id
);
element.add(option);
});
element.value = currentValue;
});
}
// Fonctions de traitement
async function summarizeDocument() {
if (!elements.summaryFile || !elements.summaryResult) return;
const fileId = elements.summaryFile.value;
if (!fileId) {
showError(elements.summaryResult, 'Veuillez sélectionner un document');
return;
}
showLoading(elements.summaryResult, 'Génération du résumé en cours...');
toggleSpinner(elements.summarySpinner, true);
disableButton(elements.summarizeBtn, true);
try {
const response = await axios.post('/api/summarize', {
file_id: fileId,
max_length: 200
}, { timeout: 120000 });
elements.summaryResult.innerHTML = `
<h3>Résumé du document</h3>
<div class="summary-content">${response.data.summary}</div>
`;
} catch (error) {
handleProcessingError(error, elements.summaryResult, 'résumé');
} finally {
toggleSpinner(elements.summarySpinner, false);
disableButton(elements.summarizeBtn, false);
}
}
async function generateCaption() {
if (!elements.captionFile || !elements.captionResult) return;
const fileId = elements.captionFile.value;
if (!fileId) {
showError(elements.captionResult, 'Veuillez sélectionner une image');
return;
}
// Afficher l'aperçu
const file = uploadedFiles.find(f => f.file_id === fileId);
if (file && elements.imagePreview) {
try {
const response = await axios.get(`/api/file/${fileId}`, { responseType: 'blob' });
const url = URL.createObjectURL(response.data);
elements.imagePreview.innerHTML = `<img src="${url}" alt="Image sélectionnée">`;
} catch (error) {
console.error("Error loading image preview:", error);
}
}
showLoading(elements.captionResult, 'Analyse de l\'image en cours...');
toggleSpinner(elements.captionSpinner, true);
disableButton(elements.captionBtn, true);
try {
const response = await axios.post('/api/caption', { file_id: fileId }, { timeout: 60000 });
elements.captionResult.innerHTML = `
<h3>Description de l'image</h3>
<p>${response.data.caption}</p>
`;
} catch (error) {
handleProcessingError(error, elements.captionResult, 'description');
} finally {
toggleSpinner(elements.captionSpinner, false);
disableButton(elements.captionBtn, false);
}
}
async function answerQuestion() {
if (!elements.questionInput || !elements.answerResult) return;
const question = elements.questionInput.value.trim();
if (!question) {
showError(elements.answerResult, 'Veuillez saisir une question');
return;
}
const fileId = elements.qaFile ? elements.qaFile.value : null;
showLoading(elements.answerResult, 'Recherche de la réponse...');
toggleSpinner(elements.qaSpinner, true);
disableButton(elements.askBtn, true);
try {
const response = await axios.post('/api/answer', {
question,
file_id: fileId || undefined
}, { timeout: 120000 });
elements.answerResult.innerHTML = `
<h3>Réponse</h3>
<div class="answer-content">${response.data.answer}</div>
`;
} catch (error) {
handleProcessingError(error, elements.answerResult, 'réponse');
} finally {
toggleSpinner(elements.qaSpinner, false);
disableButton(elements.askBtn, false);
}
}
// Fonctions utilitaires
function getFileIcon(fileType) {
const icons = {
pdf: '📄',
docx: '📝',
pptx: '📊',
xlsx: '📈',
jpg: '🖼️',
jpeg: '🖼️',
png: '🖼️'
};
return icons[fileType.toLowerCase()] || '📁';
}
function showLoading(element, message) {
if (!element) return;
element.innerHTML = `
<div class="status-message">
<div class="loading-spinner"></div>
${message}
</div>
`;
}
function showSuccess(element, message) {
if (!element) return;
element.innerHTML = `
<div class="status-message success">
${message}
</div>
`;
if (element === elements.uploadStatus) {
setTimeout(() => {
element.innerHTML = '';
}, 3000);
}
}
function showError(element, message) {
if (!element) return;
element.innerHTML = `
<div class="status-message error">
${message}
</div>
`;
}
function handleUploadError(error) {
let message = 'Échec de l\'upload';
if (error.response) {
message += `: ${error.response.data.detail || error.response.statusText}`;
} else if (error.code === 'ECONNABORTED') {
message = 'Délai d\'attente dépassé (60s) - essayez avec des fichiers plus petits';
} else if (error.message.includes('Network Error')) {
message = 'Impossible de se connecter au serveur - vérifiez votre connexion';
} else {
message += `: ${error.message}`;
}
showError(elements.uploadStatus, message);
}
function handleProcessingError(error, element, action) {
let message = `Échec de la génération du ${action}`;
if (error.response) {
message += `: ${error.response.data.detail || error.response.statusText}`;
} else if (error.code === 'ECONNABORTED') {
message = `Délai d'attente dépassé pour le ${action}`;
} else {
message += `: ${error.message}`;
}
showError(element, message);
}
function toggleSpinner(spinnerElement, show) {
if (spinnerElement) {
spinnerElement.style.display = show ? 'block' : 'none';
}
}
function disableButton(buttonElement, disable) {
if (buttonElement) {
buttonElement.disabled = disable;
buttonElement.style.opacity = disable ? 0.7 : 1;
buttonElement.style.cursor = disable ? 'not-allowed' : 'pointer';
}
}
function openTab(tabName) {
// Masquer tous les onglets
document.querySelectorAll('.tab-content').forEach(tab => {
tab.classList.remove('active');
});
// Désactiver tous les boutons
document.querySelectorAll('.tab-button').forEach(btn => {
btn.classList.remove('active');
});
// Activer l'onglet sélectionné
const tab = document.getElementById(tabName);
if (tab) tab.classList.add('active');
// Activer le bouton sélectionné
event.currentTarget.classList.add('active');
}