import { escapeAttr } from './citations.js'; export function createAssistantImageStore() { var generatedImages = {}; var generatedImageSeq = 0; function renderGeneratedImage(src, alt) { var id = 'img-' + (++generatedImageSeq); generatedImages[id] = src; return '
' + escapeAttr(alt || 'Generated image') + '' + '
' + '' + '' + '
'; } function openImagePreview(id) { var src = generatedImages[id]; if (!src) return; closeImagePreview(); var modal = document.createElement('div'); modal.className = 'assistant-image-modal'; modal.innerHTML = '
Generated clinical visual
'; document.body.appendChild(modal); } function closeImagePreview() { document.querySelectorAll('.assistant-image-modal').forEach(function (el) { el.remove(); }); } async function downloadImage(id) { var src = generatedImages[id]; if (!src) return; if (await saveWithNativeShare(src)) return; var a = document.createElement('a'); a.href = src; a.download = 'clinical-visual.png'; a.rel = 'noopener'; document.body.appendChild(a); a.click(); a.remove(); } function clear() { generatedImages = {}; closeImagePreview(); } return { renderGeneratedImage: renderGeneratedImage, openImagePreview: openImagePreview, downloadImage: downloadImage, closeImagePreview: closeImagePreview, clear: clear }; } async function saveWithNativeShare(src) { if (await shareWithWebFile(src)) return true; var plugins = window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins : null; if (!plugins) return false; if (!plugins.Filesystem && plugins.Share && !/^data:image\//i.test(src)) { try { await plugins.Share.share({ title: 'Clinical visual', text: 'Clinical Assistant generated visual', url: src, dialogTitle: 'Save or share clinical visual' }); return true; } catch (e) { return false; } } if (!plugins.Filesystem) return false; try { var base64 = await imageSourceToBase64(src); var name = 'clinical-visual-' + new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19) + '.png'; var saved = await plugins.Filesystem.writeFile({ path: name, data: base64, directory: 'DOCUMENTS' }); if (plugins.Share && saved && saved.uri) { await plugins.Share.share({ title: 'Clinical visual', text: 'Clinical Assistant generated visual', url: saved.uri, dialogTitle: 'Save or share clinical visual' }); } if (typeof window.showToast === 'function') window.showToast('Image saved to Documents', 'success'); return true; } catch (e) { if (typeof window.showToast === 'function') window.showToast('Could not save with the app. Opening browser download instead.', 'error'); return false; } } async function shareWithWebFile(src) { if (!navigator.share || !navigator.canShare || typeof File === 'undefined') return false; try { var blob = await imageSourceToBlob(src); var file = new File([blob], 'clinical-visual.png', { type: blob.type || 'image/png' }); if (!navigator.canShare({ files: [file] })) return false; await navigator.share({ files: [file], title: 'Clinical visual', text: 'Clinical Assistant generated visual' }); return true; } catch (e) { return false; } } async function imageSourceToBase64(src) { if (/^data:image\//i.test(src)) return src.split(',')[1] || ''; var blob = await imageSourceToBlob(src); return new Promise(function(resolve, reject) { var reader = new FileReader(); reader.onload = function() { resolve(String(reader.result || '').split(',')[1] || ''); }; reader.onerror = function() { reject(reader.error || new Error('Could not read image')); }; reader.readAsDataURL(blob); }); } async function imageSourceToBlob(src) { if (/^data:image\//i.test(src)) { var parts = src.split(','); var meta = parts[0] || 'data:image/png;base64'; var binary = atob(parts[1] || ''); var bytes = new Uint8Array(binary.length); for (var i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i); return new Blob([bytes], { type: (meta.match(/data:([^;]+)/) || [])[1] || 'image/png' }); } var response = await fetch(src, { credentials: 'omit' }); if (!response.ok) throw new Error('Image download failed'); return response.blob(); } export function buildContextualImagePrompt(request, lastAnswer, lastSources) { var prompt = String(request || '').trim(); if (!lastAnswer) return prompt; var sourceText = (lastSources || []).slice(0, 6).map(function (s, idx) { return '[' + (s.number || idx + 1) + '] ' + (s.title || s.resource || 'Source') + (s.page ? ', page ' + s.page : ''); }).join('\n'); return prompt + '\n\nUse this clinical answer as the required context. Do not switch topics or introduce unrelated scenes such as gardening. Create a medical teaching visual faithful to the answer.\n\nAnswer:\n' + String(lastAnswer || '').slice(0, 3000) + '\n\nSources:\n' + sourceText; } export function isImageRequest(text) { text = String(text || '').trim(); var visualNoun = /\b(image|photo|picture|visual|illustration|diagram|figure|flowchart|infographic)\b/i; return /^(image|photo|picture|visual|illustration|diagram|figure|flowchart|infographic)$/i.test(text) || (/\b(show|see|display|view)\b/i.test(text) && visualNoun.test(text) && text.split(/\s+/).length <= 8) || /\b(generate|create|draw|make|render)\b[\s\S]{0,80}\b(image|picture|illustration|visual|infographic|diagram|flowchart)\b/i.test(text) || /\b(generate|create|draw|make|render)\b[\s\S]{0,80}\b(an?|the)?\s*(algorithm|pathway|poster|teaching visual)\b/i.test(text); }