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

@@ -51,7 +51,7 @@ const SYSTEM_PROMPT = [
"Respond with the answer only. Nothing else.",
].join("\n");
async function callClaude(modelId, text, accessToken) {
async function callClaude(modelId, content, accessToken) {
return fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
dispatcher: anthropicAgent,
@@ -68,14 +68,25 @@ async function callClaude(modelId, text, accessToken) {
max_tokens: 8192,
stream: true,
system: SYSTEM_PROMPT,
messages: [{ role: 'user', content: text }],
messages: [{ role: 'user', content }],
}),
});
}
app.post('/api/chat', express.json({ limit: '10mb' }), async (req, res) => {
const { text, model = 'sonnet' } = req.body;
if (!text?.trim()) return res.status(400).json({ error: 'text required' });
app.post('/api/chat', express.json({ limit: '25mb' }), async (req, res) => {
const { text, model = 'sonnet', image } = req.body;
const hasText = text?.trim();
if (!hasText && !image) return res.status(400).json({ error: 'text or image required' });
let content;
if (image?.data && image?.media_type) {
content = [
{ type: 'image', source: { type: 'base64', media_type: image.media_type, data: image.data } },
{ type: 'text', text: hasText || 'Analyze the image and answer any questions shown in it.' },
];
} else {
content = text;
}
const accessToken = getAccessToken();
if (!accessToken) {
@@ -92,9 +103,9 @@ app.post('/api/chat', express.json({ limit: '10mb' }), async (req, res) => {
const fallbackId = MODELS.haiku;
try {
let apiResp = await callClaude(primaryId, text, accessToken);
let apiResp = await callClaude(primaryId, content, accessToken);
if (apiResp.status === 429 && primaryId !== fallbackId) {
apiResp = await callClaude(fallbackId, text, accessToken);
apiResp = await callClaude(fallbackId, content, accessToken);
}
if (!apiResp.ok) {
const errText = await apiResp.text();