File size: 4,335 Bytes
313d127
 
 
 
 
 
d61e61c
313d127
d61e61c
 
 
 
 
 
313d127
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d61e61c
 
 
 
 
 
 
 
 
313d127
 
 
 
d61e61c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313d127
 
 
 
 
 
 
d61e61c
313d127
 
d61e61c
313d127
 
 
 
 
d61e61c
 
 
313d127
 
d61e61c
313d127
d61e61c
313d127
 
 
 
 
 
 
 
 
d61e61c
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
const dropZone = document.getElementById('dropZone');
const fileInput = document.getElementById('fileInput');
const previewImg = document.getElementById('previewImg');
const uploadPrompt = document.getElementById('uploadPrompt');
const captionBtn = document.getElementById('captionBtn');
let currentFile = null;
let currentMode = 'detailed';

function setMode(mode) {
    currentMode = mode;
    document.querySelectorAll('.mode-btn').forEach(b => {
        b.classList.toggle('active', b.dataset.mode === mode);
    });
}

fileInput.addEventListener('change', (e) => handleFile(e.target.files[0]));

dropZone.addEventListener('dragover', (e) => { e.preventDefault(); dropZone.style.borderColor = 'var(--accent)'; });
dropZone.addEventListener('dragleave', () => { dropZone.style.borderColor = ''; });
dropZone.addEventListener('drop', (e) => {
    e.preventDefault();
    dropZone.style.borderColor = '';
    if (e.dataTransfer.files.length) handleFile(e.dataTransfer.files[0]);
});

function handleFile(file) {
    if (!file || !file.type.startsWith('image/')) return;
    currentFile = file;
    const reader = new FileReader();
    reader.onload = (e) => {
        previewImg.src = e.target.result;
        previewImg.classList.remove('hidden');
        uploadPrompt.style.display = 'none';
        dropZone.classList.add('has-image');
        captionBtn.disabled = false;

        // Show image meta
        const img = new window.Image();
        img.onload = () => {
            const meta = document.getElementById('imageMeta');
            meta.classList.remove('hidden');
            meta.textContent = `${img.width} x ${img.height} | ${file.name} | ${(file.size / 1024).toFixed(1)} KB`;
        };
        img.src = e.target.result;
    };
    reader.readAsDataURL(file);
}

async function loadDemoImage(url, name) {
    captionBtn.disabled = true;
    captionBtn.textContent = 'Loading image...';

    try {
        const res = await fetch(url);
        const blob = await res.blob();
        currentFile = new File([blob], name + '.jpg', { type: blob.type });

        const reader = new FileReader();
        reader.onload = (e) => {
            previewImg.src = e.target.result;
            previewImg.classList.remove('hidden');
            uploadPrompt.style.display = 'none';
            dropZone.classList.add('has-image');

            const meta = document.getElementById('imageMeta');
            meta.classList.remove('hidden');
            meta.textContent = `${name} | ${(blob.size / 1024).toFixed(1)} KB`;

            captionBtn.disabled = false;
            captionBtn.textContent = 'Generate Captions';
        };
        reader.readAsDataURL(currentFile);
    } catch (err) {
        captionBtn.textContent = 'Failed to load demo image';
        setTimeout(() => { captionBtn.textContent = 'Generate Captions'; }, 2000);
    }
}

async function generateCaption() {
    if (!currentFile) return;
    captionBtn.disabled = true;
    captionBtn.textContent = 'Generating...';

    const formData = new FormData();
    formData.append('file', currentFile);
    formData.append('mode', currentMode);

    try {
        const res = await fetch('/api/caption', { method: 'POST', body: formData });
        const data = await res.json();

        const el = document.getElementById('result');
        el.classList.remove('hidden');

        const modeLabels = { quick: 'Quick', detailed: 'Detailed', creative: 'Creative' };
        document.getElementById('modeTag').textContent = modeLabels[data.mode] + ' | ' + data.size[0] + 'x' + data.size[1];
        document.getElementById('timeTag').textContent = data.ms + 'ms | ' + data.beams + ' beams';

        document.getElementById('captionList').innerHTML = data.captions.map((c, i) => `
            <div class="caption-item ${i === 0 ? 'best' : ''}">
                <span class="caption-num">${i + 1}.</span>
                <span>${escapeHtml(c)}${i === 0 ? '<span class="caption-badge">BEST</span>' : ''}</span>
            </div>
        `).join('');
    } catch (err) {
        alert('Error: ' + err.message);
    } finally {
        captionBtn.disabled = false;
        captionBtn.textContent = 'Generate Captions';
    }
}

function escapeHtml(text) {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
}