curaflow/backend/server.js

171 lines
5.8 KiB
JavaScript

const express = require('express');
const path = require('path');
const botLogic = require('./botLogic');
const configManager = require('./configManager');
const { getTemporalClient } = require('./temporalClient');
const { v4: uuidv4 } = require('uuid');
const app = express();
const port = 3000;
app.use(express.json());
// Serve static files
app.use(express.static(path.join(__dirname, '../')));
// Primary Routes
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, '../login.html'));
});
app.get('/admin', (req, res) => {
res.sendFile(path.join(__dirname, '../admin.html'));
});
app.get('/dashboard', (req, res) => {
res.sendFile(path.join(__dirname, '../dashboard.html'));
});
// Multi-tenant Config API
app.get('/api/config/:tenantId', (req, res) => {
const config = configManager.getTenantConfig(req.params.tenantId);
res.json(config);
});
// Mock WhatsApp Webhook
app.post('/whatsapp/webhook', async (req, res) => {
const { from, body } = req.body;
console.log(`Received message from ${from}: ${body}`);
const response = await botLogic.handleMessage(from, body);
// In a real app, you'd call Twilio/Meta API here to send the reply
res.json({
success: true,
reply: response.reply,
buttons: response.buttons || []
});
});
// AI Scribe Endpoints
app.post('/api/ai/scribe/start', async (req, res) => {
try {
const { dictation } = req.body;
if (!dictation) return res.status(400).json({ error: 'Dictation is required' });
const temporalClient = await getTemporalClient();
const jobId = `scribe-${uuidv4()}`;
console.log(`[AI Scribe] Starting job ${jobId} for dictation of length ${dictation.length}`);
// Start the workflow asynchronously
await temporalClient.workflow.start('ClinicalIntakeWorkflow', {
args: [dictation],
taskQueue: 'curaflow-tasks',
workflowId: jobId,
});
res.json({ success: true, jobId });
} catch (err) {
console.error('[AI Scribe] Start Error:', err);
res.status(500).json({ error: 'Failed to start AI Scribe job' });
}
});
app.get('/api/ai/scribe/status/:jobId', async (req, res) => {
try {
const { jobId } = req.params;
const temporalClient = await getTemporalClient();
const handle = temporalClient.workflow.getHandle(jobId);
const description = await handle.describe();
// Check if completed
if (description.status.name === 'COMPLETED') {
const result = await handle.result();
return res.json({ status: 'COMPLETED', result });
} else if (description.status.name === 'FAILED') {
return res.json({ status: 'FAILED' });
}
return res.json({ status: description.status.name });
} catch (err) {
// If not found or error
console.error(`[AI Scribe] Status Error for ${req.params.jobId}:`, err);
res.status(500).json({ error: 'Failed to get job status' });
}
});
// Lab Watcher Endpoints
app.post('/api/ai/lab/watch/start', async (req, res) => {
try {
const { patientId, baselineData } = req.body;
if (!patientId) return res.status(400).json({ error: 'Patient ID is required' });
const temporalClient = await getTemporalClient();
const workflowId = `lab-watcher-${patientId}`;
// Ensure we don't start it twice if it's already running
try {
const handle = temporalClient.workflow.getHandle(workflowId);
const desc = await handle.describe();
if (desc.status.name === 'RUNNING') {
return res.json({ success: true, message: 'Watcher already running' });
}
} catch (e) {
// Not found, so we proceed to start it
}
await temporalClient.workflow.start('LabResultWatcherWorkflow', {
args: [baselineData || { baseline: "Patient is healthy", medications: [] }],
taskQueue: 'curaflow-tasks',
workflowId: workflowId,
});
res.json({ success: true });
} catch (err) {
console.error('[AI Lab Watcher] Start Error:', err);
res.status(500).json({ error: 'Failed to start AI Lab Watcher' });
}
});
app.post('/api/ai/lab/result/:patientId', async (req, res) => {
try {
const { patientId } = req.params;
const { result } = req.body;
if (!result) return res.status(400).json({ error: 'Lab result string is required' });
const temporalClient = await getTemporalClient();
const workflowId = `lab-watcher-${patientId}`;
const handle = temporalClient.workflow.getHandle(workflowId);
await handle.signal('add_lab_result', result);
res.json({ success: true });
} catch (err) {
console.error(`[AI Lab Watcher] Signal Error for ${req.params.patientId}:`, err);
res.status(500).json({ error: 'Failed to send lab result to AI Watcher' });
}
});
app.get('/api/ai/lab/alerts/:patientId', async (req, res) => {
try {
const { patientId } = req.params;
const temporalClient = await getTemporalClient();
const workflowId = `lab-watcher-${patientId}`;
try {
const handle = temporalClient.workflow.getHandle(workflowId);
const alerts = await handle.query('get_alerts');
res.json({ success: true, alerts });
} catch (e) {
// Workflow might not be running
res.json({ success: true, alerts: [] });
}
} catch (err) {
console.error(`[AI Lab Watcher] Query Error for ${req.params.patientId}:`, err);
res.status(500).json({ error: 'Failed to fetch alerts' });
}
});
app.listen(port, '0.0.0.0', () => {
console.log(`Curio WhatsApp Mock Server running at http://0.0.0.0:${port}`);
});