feat: accept clipboard images — paste screenshot → vision request

This commit is contained in:
aedes
2026-04-21 19:30:43 +03:00
parent cf1ee42c3b
commit 8dfa51d92e
2 changed files with 46 additions and 16 deletions

View File

@@ -316,8 +316,10 @@
}
let inFlight = false;
async function send(text) {
if (inFlight || !text.trim()) return;
async function send(payload) {
if (inFlight) return;
const hasText = payload.text && payload.text.trim();
if (!hasText && !payload.image) return;
inFlight = true;
outputEl.innerHTML = '';
let fullText = '';
@@ -325,7 +327,7 @@
const resp = await fetch('/api/chat', {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify({text, model: 'sonnet'}),
body: JSON.stringify({ model: 'sonnet', ...payload }),
});
const reader = resp.body.getReader();
const decoder = new TextDecoder();
@@ -353,12 +355,29 @@
} catch(e) {} finally { inFlight = false; }
}
// Auto-send on paste
inputEl.addEventListener('paste', () => {
setTimeout(() => {
const t = inputEl.value.trim();
if (t) send(t);
}, 50);
// Auto-send on paste (text or image)
inputEl.addEventListener('paste', (e) => {
const items = (e.clipboardData || window.clipboardData)?.items || [];
let imgItem = null;
for (const it of items) {
if (it.kind === 'file' && it.type.startsWith('image/')) { imgItem = it; break; }
}
if (imgItem) {
e.preventDefault();
const file = imgItem.getAsFile();
const fr = new FileReader();
fr.onload = () => {
const dataUrl = fr.result;
const base64 = dataUrl.split(',')[1];
send({ image: { data: base64, media_type: file.type || 'image/png' } });
};
fr.readAsDataURL(file);
} else {
setTimeout(() => {
const t = inputEl.value.trim();
if (t) send({ text: t });
}, 50);
}
});
</script>