extract assistant frontend api client
This commit is contained in:
parent
7b04546a6e
commit
6cfad65639
2 changed files with 100 additions and 43 deletions
74
public/js/assistant/api.js
Normal file
74
public/js/assistant/api.js
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
function authHeaders() {
|
||||||
|
return window.getAuthHeaders ? window.getAuthHeaders() : { 'Content-Type': 'application/json' };
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseJsonWithStatus(response) {
|
||||||
|
return response.json().catch(function () { return {}; }).then(function(data) {
|
||||||
|
data._status = response.status;
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchAssistantStatus() {
|
||||||
|
return fetch('/api/clinical-assistant/status', { headers: authHeaders(), credentials: 'same-origin' })
|
||||||
|
.then(function(r) { return r.json(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchAssistantExamples() {
|
||||||
|
return fetch('/api/clinical-assistant/examples', { headers: authHeaders(), credentials: 'same-origin' })
|
||||||
|
.then(function(r) { return r.json(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function openAssistantStream(payload) {
|
||||||
|
return fetch('/api/clinical-assistant/chat/stream', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: authHeaders(),
|
||||||
|
credentials: 'same-origin',
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchAssistantChat(payload) {
|
||||||
|
return fetch('/api/clinical-assistant/chat', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: authHeaders(),
|
||||||
|
credentials: 'same-origin',
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
}).then(parseJsonWithStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function requestAssistantImage(prompt) {
|
||||||
|
return fetch('/api/clinical-assistant/image', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: authHeaders(),
|
||||||
|
credentials: 'same-origin',
|
||||||
|
body: JSON.stringify({ prompt: prompt })
|
||||||
|
}).then(function(r) { return r.json(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveAssistantChat(payload) {
|
||||||
|
return fetch('/api/clinical-assistant/chats', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: authHeaders(),
|
||||||
|
credentials: 'same-origin',
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
}).then(parseJsonWithStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchSavedAssistantChats() {
|
||||||
|
return fetch('/api/clinical-assistant/chats', { headers: authHeaders(), credentials: 'same-origin' })
|
||||||
|
.then(function(r) { return r.json(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchSavedAssistantChat(id) {
|
||||||
|
return fetch('/api/clinical-assistant/chats/' + encodeURIComponent(id), { headers: authHeaders(), credentials: 'same-origin' })
|
||||||
|
.then(parseJsonWithStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteSavedAssistantChat(id) {
|
||||||
|
return fetch('/api/clinical-assistant/chats/' + encodeURIComponent(id), {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: authHeaders(),
|
||||||
|
credentials: 'same-origin'
|
||||||
|
}).then(function(r) { return r.json(); });
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,17 @@
|
||||||
// ============================================================
|
// ============================================================
|
||||||
import { EMPTY_PROMPT_SETS } from './assistant/data.js';
|
import { EMPTY_PROMPT_SETS } from './assistant/data.js';
|
||||||
import { escapeAttr, escapeHtml, renderAssistantMarkdown } from './assistant/citations.js';
|
import { escapeAttr, escapeHtml, renderAssistantMarkdown } from './assistant/citations.js';
|
||||||
|
import {
|
||||||
|
deleteSavedAssistantChat,
|
||||||
|
fetchAssistantChat,
|
||||||
|
fetchAssistantExamples,
|
||||||
|
fetchAssistantStatus,
|
||||||
|
fetchSavedAssistantChat,
|
||||||
|
fetchSavedAssistantChats,
|
||||||
|
openAssistantStream,
|
||||||
|
requestAssistantImage,
|
||||||
|
saveAssistantChat
|
||||||
|
} from './assistant/api.js';
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
@ -68,8 +79,7 @@ import { escapeAttr, escapeHtml, renderAssistantMarkdown } from './assistant/cit
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadStatus() {
|
function loadStatus() {
|
||||||
fetch('/api/clinical-assistant/status', { headers: getAuthHeaders(), credentials: 'same-origin' })
|
fetchAssistantStatus()
|
||||||
.then(function (r) { return r.json(); })
|
|
||||||
.then(function (data) {
|
.then(function (data) {
|
||||||
var label = document.getElementById('assistant-model-label');
|
var label = document.getElementById('assistant-model-label');
|
||||||
if (label && data.success) {
|
if (label && data.success) {
|
||||||
|
|
@ -82,8 +92,7 @@ import { escapeAttr, escapeHtml, renderAssistantMarkdown } from './assistant/cit
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadExamples() {
|
function loadExamples() {
|
||||||
fetch('/api/clinical-assistant/examples', { headers: getAuthHeaders(), credentials: 'same-origin' })
|
fetchAssistantExamples()
|
||||||
.then(function (r) { return r.json(); })
|
|
||||||
.then(function (data) {
|
.then(function (data) {
|
||||||
if (!data.success || !Array.isArray(data.examples) || !data.examples.length) return;
|
if (!data.success || !Array.isArray(data.examples) || !data.examples.length) return;
|
||||||
dynamicExamples = data.examples;
|
dynamicExamples = data.examples;
|
||||||
|
|
@ -150,12 +159,7 @@ import { escapeAttr, escapeHtml, renderAssistantMarkdown } from './assistant/cit
|
||||||
}
|
}
|
||||||
|
|
||||||
async function streamAssistantResponse(payload, loading) {
|
async function streamAssistantResponse(payload, loading) {
|
||||||
var response = await fetch('/api/clinical-assistant/chat/stream', {
|
var response = await openAssistantStream(payload);
|
||||||
method: 'POST',
|
|
||||||
headers: getAuthHeaders(),
|
|
||||||
credentials: 'same-origin',
|
|
||||||
body: JSON.stringify(payload)
|
|
||||||
});
|
|
||||||
if (!response.ok || !response.body) {
|
if (!response.ok || !response.body) {
|
||||||
var fallback = await response.json().catch(function () { return {}; });
|
var fallback = await response.json().catch(function () { return {}; });
|
||||||
throw new Error(fallback.error || ('Request failed (' + response.status + ')'));
|
throw new Error(fallback.error || ('Request failed (' + response.status + ')'));
|
||||||
|
|
@ -250,14 +254,8 @@ import { escapeAttr, escapeHtml, renderAssistantMarkdown } from './assistant/cit
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchAssistantFallback(payload) {
|
async function fetchAssistantFallback(payload) {
|
||||||
var response = await fetch('/api/clinical-assistant/chat', {
|
var data = await fetchAssistantChat(payload);
|
||||||
method: 'POST',
|
if (!data.success) throw new Error(data.error || ('Request failed (' + data._status + ')'));
|
||||||
headers: getAuthHeaders(),
|
|
||||||
credentials: 'same-origin',
|
|
||||||
body: JSON.stringify(payload)
|
|
||||||
});
|
|
||||||
var data = await response.json().catch(function () { return {}; });
|
|
||||||
if (!response.ok || !data.success) throw new Error(data.error || ('Request failed (' + response.status + ')'));
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -471,11 +469,7 @@ import { escapeAttr, escapeHtml, renderAssistantMarkdown } from './assistant/cit
|
||||||
if (fromChat) setBusy(true, 'Generating image...');
|
if (fromChat) setBusy(true, 'Generating image...');
|
||||||
var loading = fromChat ? appendLoadingMessage('Generating image', 'Creating the requested clinical visual...') : null;
|
var loading = fromChat ? appendLoadingMessage('Generating image', 'Creating the requested clinical visual...') : null;
|
||||||
if (out) out.innerHTML = '<p class="assistant-muted"><i class="fas fa-spinner fa-spin"></i> Generating image...</p>';
|
if (out) out.innerHTML = '<p class="assistant-muted"><i class="fas fa-spinner fa-spin"></i> Generating image...</p>';
|
||||||
fetch('/api/clinical-assistant/image', {
|
requestAssistantImage(prompt)
|
||||||
method: 'POST', headers: getAuthHeaders(), credentials: 'same-origin',
|
|
||||||
body: JSON.stringify({ prompt: prompt })
|
|
||||||
})
|
|
||||||
.then(function (r) { return r.json(); })
|
|
||||||
.then(function (data) {
|
.then(function (data) {
|
||||||
if (!data.success) throw new Error(data.error || 'Image generation failed');
|
if (!data.success) throw new Error(data.error || 'Image generation failed');
|
||||||
var src = data.imageUrl || data.url || (data.base64 ? ('data:image/png;base64,' + data.base64) : '');
|
var src = data.imageUrl || data.url || (data.base64 ? ('data:image/png;base64,' + data.base64) : '');
|
||||||
|
|
@ -762,19 +756,13 @@ import { escapeAttr, escapeHtml, renderAssistantMarkdown } from './assistant/cit
|
||||||
var titleEl = document.getElementById('assistant-save-title');
|
var titleEl = document.getElementById('assistant-save-title');
|
||||||
var title = String(titleEl && titleEl.value || deriveChatTitle()).trim() || deriveChatTitle();
|
var title = String(titleEl && titleEl.value || deriveChatTitle()).trim() || deriveChatTitle();
|
||||||
setBusy(true, 'Saving chat...');
|
setBusy(true, 'Saving chat...');
|
||||||
fetch('/api/clinical-assistant/chats', {
|
saveAssistantChat({
|
||||||
method: 'POST',
|
title: title,
|
||||||
headers: getAuthHeaders(),
|
messages: messages,
|
||||||
credentials: 'same-origin',
|
sources: lastSources,
|
||||||
body: JSON.stringify({
|
lastAnswer: lastAnswer,
|
||||||
title: title,
|
generatedImage: imageForSavedChatPayload(lastGeneratedImageSrc)
|
||||||
messages: messages,
|
|
||||||
sources: lastSources,
|
|
||||||
lastAnswer: lastAnswer,
|
|
||||||
generatedImage: imageForSavedChatPayload(lastGeneratedImageSrc)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.then(function (r) { return r.json().then(function (data) { data._status = r.status; return data; }); })
|
|
||||||
.then(function (data) {
|
.then(function (data) {
|
||||||
setBusy(false, 'Ready');
|
setBusy(false, 'Ready');
|
||||||
if (!data.success) throw new Error(data.error || 'Save failed');
|
if (!data.success) throw new Error(data.error || 'Save failed');
|
||||||
|
|
@ -805,8 +793,7 @@ import { escapeAttr, escapeHtml, renderAssistantMarkdown } from './assistant/cit
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadSavedChats() {
|
function loadSavedChats() {
|
||||||
fetch('/api/clinical-assistant/chats', { headers: getAuthHeaders(), credentials: 'same-origin' })
|
fetchSavedAssistantChats()
|
||||||
.then(function (r) { return r.json(); })
|
|
||||||
.then(function (data) { if (data.success) renderSavedChats(data.chats || []); })
|
.then(function (data) { if (data.success) renderSavedChats(data.chats || []); })
|
||||||
.catch(function () {});
|
.catch(function () {});
|
||||||
}
|
}
|
||||||
|
|
@ -830,8 +817,7 @@ import { escapeAttr, escapeHtml, renderAssistantMarkdown } from './assistant/cit
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadSavedChat(id) {
|
function loadSavedChat(id) {
|
||||||
fetch('/api/clinical-assistant/chats/' + encodeURIComponent(id), { headers: getAuthHeaders(), credentials: 'same-origin' })
|
fetchSavedAssistantChat(id)
|
||||||
.then(function (r) { return r.json().then(function (data) { data._status = r.status; return data; }); })
|
|
||||||
.then(function (data) {
|
.then(function (data) {
|
||||||
if (!data.success) throw new Error(data.error || 'Load failed');
|
if (!data.success) throw new Error(data.error || 'Load failed');
|
||||||
restoreSavedChat(data.chat && data.chat.payload || {});
|
restoreSavedChat(data.chat && data.chat.payload || {});
|
||||||
|
|
@ -853,10 +839,7 @@ import { escapeAttr, escapeHtml, renderAssistantMarkdown } from './assistant/cit
|
||||||
}, 5000);
|
}, 5000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fetch('/api/clinical-assistant/chats/' + encodeURIComponent(id), {
|
deleteSavedAssistantChat(id)
|
||||||
method: 'DELETE', headers: getAuthHeaders(), credentials: 'same-origin'
|
|
||||||
})
|
|
||||||
.then(function (r) { return r.json(); })
|
|
||||||
.then(function () { loadSavedChats(); if (typeof showToast === 'function') showToast('Deleted saved chat', 'success'); })
|
.then(function () { loadSavedChats(); if (typeof showToast === 'function') showToast('Deleted saved chat', 'success'); })
|
||||||
.catch(function () { if (typeof showToast === 'function') showToast('Delete failed', 'error'); });
|
.catch(function () { if (typeof showToast === 'function') showToast('Delete failed', 'error'); });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue