Fix generated image mobile downloads
All checks were successful
Forgejo Android APK / Build signed APK (push) Successful in 2m21s
All checks were successful
Forgejo Android APK / Build signed APK (push) Successful in 2m21s
This commit is contained in:
parent
80139d9a82
commit
2ca969e099
8 changed files with 49 additions and 14 deletions
|
|
@ -9,8 +9,8 @@ android {
|
|||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
// Version values below are overwritten by scripts/release.sh from
|
||||
// the root package.json. versionCode auto-increments per release.
|
||||
versionCode 714012
|
||||
versionName "7.14.12"
|
||||
versionCode 714013
|
||||
versionName "7.14.13"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
aaptOptions {
|
||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||
|
|
|
|||
4
mobile/package-lock.json
generated
4
mobile/package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "pedscribe-mobile",
|
||||
"version": "7.14.12",
|
||||
"version": "7.14.13",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pedscribe-mobile",
|
||||
"version": "7.14.12",
|
||||
"version": "7.14.13",
|
||||
"dependencies": {
|
||||
"@aparajita/capacitor-biometric-auth": "^8.0.0",
|
||||
"@capacitor/android": "^6.0.0",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "pedscribe-mobile",
|
||||
"version": "7.14.12",
|
||||
"version": "7.14.13",
|
||||
"description": "PedScribe native mobile app — Capacitor wrapper for Pediatric AI Scribe",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
|
|
|||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "pediatric-ai-scribe",
|
||||
"version": "7.14.12",
|
||||
"version": "7.14.13",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pediatric-ai-scribe",
|
||||
"version": "7.14.12",
|
||||
"version": "7.14.13",
|
||||
"dependencies": {
|
||||
"@marp-team/marp-cli": "^4.3.1",
|
||||
"@marp-team/marp-core": "^4.3.0",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "pediatric-ai-scribe",
|
||||
"version": "7.14.12",
|
||||
"version": "7.14.13",
|
||||
"description": "AI-powered pediatric clinical documentation platform",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ export function createAssistantImageStore() {
|
|||
var generatedImageSeq = 0;
|
||||
var previewKeyHandler = null;
|
||||
|
||||
function renderGeneratedImage(src, alt) {
|
||||
function renderGeneratedImage(src, alt, downloadUrl) {
|
||||
var id = 'img-' + (++generatedImageSeq);
|
||||
generatedImages[id] = src;
|
||||
generatedImages[id] = { src: src, downloadUrl: downloadUrl || '' };
|
||||
return '<div class="assistant-generated-image"><img src="' + escapeAttr(src) + '" alt="' + escapeAttr(alt || 'Generated image') + '">' +
|
||||
'<div class="assistant-image-actions">' +
|
||||
'<button type="button" class="btn-sm btn-ghost" data-assistant-open-image="' + escapeAttr(id) + '"><i class="fas fa-expand"></i> Preview</button>' +
|
||||
|
|
@ -16,7 +16,8 @@ export function createAssistantImageStore() {
|
|||
}
|
||||
|
||||
function openImagePreview(id) {
|
||||
var src = generatedImages[id];
|
||||
var item = generatedImages[id];
|
||||
var src = item && (item.src || item);
|
||||
if (!src) return;
|
||||
closeImagePreview();
|
||||
var modal = document.createElement('div');
|
||||
|
|
@ -41,10 +42,16 @@ export function createAssistantImageStore() {
|
|||
}
|
||||
|
||||
async function downloadImage(id) {
|
||||
var src = generatedImages[id];
|
||||
var item = generatedImages[id];
|
||||
var src = item && (item.src || item);
|
||||
var downloadUrl = item && item.downloadUrl;
|
||||
if (!src) return;
|
||||
try {
|
||||
if (await saveWithNativeShare(src)) return;
|
||||
if (downloadUrl) {
|
||||
downloadFromServer(downloadUrl);
|
||||
return;
|
||||
}
|
||||
if (isNativeApp()) {
|
||||
if (typeof window.showToast === 'function') window.showToast('Image saving is not available in this app build yet. Update the app and try again.', 'error');
|
||||
return;
|
||||
|
|
@ -160,6 +167,16 @@ async function downloadWithBrowser(src) {
|
|||
setTimeout(function() { URL.revokeObjectURL(objectUrl); }, 60000);
|
||||
}
|
||||
|
||||
function downloadFromServer(url) {
|
||||
var a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'clinical-visual.png';
|
||||
a.rel = 'noopener';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
}
|
||||
|
||||
function isMobileBrowser() {
|
||||
return !isNativeApp() && /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent || '');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -492,10 +492,11 @@ import {
|
|||
if (!src) throw new Error('No image returned');
|
||||
lastGeneratedImageSrc = src;
|
||||
exporter.invalidate();
|
||||
if (out) out.innerHTML = imageStore.renderGeneratedImage(src, 'Generated clinical visual');
|
||||
var downloadUrl = data.downloadUrl || '';
|
||||
if (out) out.innerHTML = imageStore.renderGeneratedImage(src, 'Generated clinical visual', downloadUrl);
|
||||
if (fromChat) {
|
||||
setBusy(false, 'Ready');
|
||||
var html = imageStore.renderGeneratedImage(src, 'Generated clinical visual');
|
||||
var html = imageStore.renderGeneratedImage(src, 'Generated clinical visual', downloadUrl);
|
||||
replaceLoadingMessage(loading, html, [], [], true);
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -325,6 +325,7 @@ router.get('/clinical-assistant/image/jobs/:id', async function(req, res) {
|
|||
imageUrl: job.imageUrl || null,
|
||||
url: job.url || null,
|
||||
base64: job.base64 || null,
|
||||
downloadUrl: job.status === 'done' && job.base64 ? '/api/clinical-assistant/image/jobs/' + encodeURIComponent(job.id) + '/download' : null,
|
||||
error: job.error || null
|
||||
});
|
||||
} catch (e) {
|
||||
|
|
@ -332,6 +333,22 @@ router.get('/clinical-assistant/image/jobs/:id', async function(req, res) {
|
|||
}
|
||||
});
|
||||
|
||||
router.get('/clinical-assistant/image/jobs/:id/download', async function(req, res) {
|
||||
try {
|
||||
var job = await getImageJob(req.params.id);
|
||||
if (!job || String(job.userId) !== String(req.user.id) || job.status !== 'done' || !job.base64) {
|
||||
return res.status(404).json({ error: 'Image job not found' });
|
||||
}
|
||||
var buffer = Buffer.from(String(job.base64), 'base64');
|
||||
res.setHeader('Content-Type', 'image/png');
|
||||
res.setHeader('Content-Disposition', 'attachment; filename="clinical-visual.png"');
|
||||
res.setHeader('Cache-Control', 'private, max-age=900');
|
||||
res.send(buffer);
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: 'Image download failed' });
|
||||
}
|
||||
});
|
||||
|
||||
async function prepareAssistantChat(body) {
|
||||
body = body || {};
|
||||
var message = String(body.message || '').trim();
|
||||
|
|
|
|||
Loading…
Reference in a new issue