Bluesky app fork with some witchin' additions 馃挮
at main 61 lines 1.8 kB view raw
1import {DEFAULT_ALT_TEXT_AI_MODEL, MAX_ALT_TEXT} from '#/lib/constants' 2import {logger} from '#/logger' 3 4export async function generateAltText( 5 apiKey: string, 6 model: string, 7 imageBase64: string, 8 imageMimeType: string, 9): Promise<string> { 10 const response = await fetch( 11 'https://openrouter.ai/api/v1/chat/completions', 12 { 13 method: 'POST', 14 headers: { 15 Authorization: `Bearer ${apiKey}`, 16 'Content-Type': 'application/json', 17 'HTTP-Referer': 'https://witchsky.app', 18 'X-Title': 'Witchsky', 19 }, 20 body: JSON.stringify({ 21 model: model || DEFAULT_ALT_TEXT_AI_MODEL, 22 messages: [ 23 { 24 role: 'user', 25 content: [ 26 { 27 type: 'text', 28 text: `Generate a concise, descriptive alt text for this image, also extract text if needed. The alt text should be clear and helpful for screen readers. Keep it under ${MAX_ALT_TEXT} characters. Only respond with the alt text itself, no explanations or quotes.`, 29 }, 30 { 31 type: 'image_url', 32 image_url: { 33 url: `data:${imageMimeType};base64,${imageBase64}`, 34 }, 35 }, 36 ], 37 }, 38 ], 39 max_tokens: MAX_ALT_TEXT, 40 }), 41 }, 42 ) 43 44 if (!response.ok) { 45 const errorText = await response.text() 46 logger.error('OpenRouter API error', { 47 status: response.status, 48 error: errorText, 49 }) 50 throw new Error(`OpenRouter API error: ${response.status}`) 51 } 52 53 const data = await response.json() 54 const altText = data.choices?.[0]?.message?.content?.trim() 55 56 if (!altText) { 57 throw new Error('No alt text generated') 58 } 59 60 return altText 61}