// ============================================================ // MEMORIES ROUTES — User template/memory storage // ============================================================ var express = require('express'); var router = express.Router(); var db = require('../db/database'); var { authMiddleware } = require('../middleware/auth'); var logger = require('../utils/logger'); router.use(authMiddleware); var VALID_CATEGORIES = [ 'physical_exam', 'ros', 'encounter_format', 'family_history', 'assessment_plan', 'custom', 'template_soap', 'template_hpi', 'template_wellvisit', 'template_sickvisit', 'correction_soap', 'correction_hpi', 'correction_encounter', 'correction_wellvisit', 'correction_sickvisit' ]; // ── GET all memories for current user ─────────────────────────────────── router.get('/memories', async function(req, res) { try { var rows = await db.all( 'SELECT id, category, name, content, created_at, updated_at FROM user_memories WHERE user_id = $1 ORDER BY category, name', [req.user.id] ); res.json({ success: true, memories: rows }); } catch (e) { logger.error('GET /memories', e.message); res.status(500).json({ error: e.message }); } }); // ── POST create memory ─────────────────────────────────────────────────── router.post('/memories', async function(req, res) { try { var { name, category, content } = req.body; if (!name || !name.trim()) return res.status(400).json({ error: 'Name required' }); if (!content || !content.trim()) return res.status(400).json({ error: 'Content required' }); var cat = VALID_CATEGORIES.includes(category) ? category : 'custom'; // Limit per user var count = await db.get('SELECT COUNT(*) as cnt FROM user_memories WHERE user_id = $1', [req.user.id]); if (count && parseInt(count.cnt) >= 200) return res.status(400).json({ error: 'Maximum 200 memories per user' }); var result = await db.run( 'INSERT INTO user_memories (user_id, category, name, content) VALUES ($1,$2,$3,$4)', [req.user.id, cat, name.trim().substring(0, 100), content.trim().substring(0, 5000)] ); res.json({ success: true, id: result.lastInsertRowid }); } catch (e) { logger.error('POST /memories', e.message); res.status(500).json({ error: e.message }); } }); // ── PUT update memory ──────────────────────────────────────────────────── router.put('/memories/:id', async function(req, res) { try { var { name, category, content } = req.body; var cat = VALID_CATEGORIES.includes(category) ? category : 'custom'; await db.run( 'UPDATE user_memories SET name=$1, category=$2, content=$3, updated_at=NOW() WHERE id=$4 AND user_id=$5', [ (name || '').trim().substring(0, 100), cat, (content || '').trim().substring(0, 5000), req.params.id, req.user.id ] ); res.json({ success: true }); } catch (e) { logger.error('PUT /memories/:id', e.message); res.status(500).json({ error: e.message }); } }); // ── DELETE memory ──────────────────────────────────────────────────────── router.delete('/memories/:id', async function(req, res) { try { await db.run('DELETE FROM user_memories WHERE id = $1 AND user_id = $2', [req.params.id, req.user.id]); res.json({ success: true }); } catch (e) { logger.error('DELETE /memories/:id', e.message); res.status(500).json({ error: e.message }); } }); // ── GET memories as prompt context (for AI generation) ────────────────── router.get('/memories/context', async function(req, res) { try { var rows = await db.all( 'SELECT category, name, content FROM user_memories WHERE user_id = $1 ORDER BY category', [req.user.id] ); if (rows.length === 0) return res.json({ success: true, context: '' }); var templates = []; var corrections = []; rows.forEach(function(r) { if (r.category.startsWith('correction_')) corrections.push(r); else templates.push(r); }); var context = ''; if (templates.length > 0) { context += '\n\nPHYSICIAN TEMPLATES AND PREFERENCES:\n'; templates.forEach(function(r) { context += '--- ' + r.category.toUpperCase().replace(/_/g, ' ') + ': ' + r.name + ' ---\n' + r.content + '\n\n'; }); } if (corrections.length > 0) { context += '\n\nPHYSICIAN CORRECTION HISTORY (learn from these preferences — apply similar corrections to future outputs):\n'; corrections.slice(-20).forEach(function(r) { context += '--- CORRECTION (' + r.category.replace('correction_', '').toUpperCase() + '): ' + r.name + ' ---\n' + r.content + '\n\n'; }); } res.json({ success: true, context: context.trim() }); } catch (e) { logger.error('GET /memories/context', e.message); res.status(500).json({ error: e.message }); } }); // ── POST auto-save correction (Dragon-like learning) ────────────────── router.post('/memories/correction', async function(req, res) { try { var { section, original_snippet, corrected_snippet } = req.body; if (!section || !original_snippet || !corrected_snippet) { return res.status(400).json({ error: 'section, original_snippet, and corrected_snippet required' }); } if (original_snippet.trim() === corrected_snippet.trim()) { return res.json({ success: true, skipped: true }); } var cat = 'correction_' + section; if (!VALID_CATEGORIES.includes(cat)) cat = 'correction_encounter'; // Limit corrections per category: keep only latest 20 var existing = await db.all( 'SELECT id FROM user_memories WHERE user_id = $1 AND category = $2 ORDER BY created_at ASC', [req.user.id, cat] ); if (existing.length >= 20) { // Delete oldest to make room var toDelete = existing.slice(0, existing.length - 19); for (var i = 0; i < toDelete.length; i++) { await db.run('DELETE FROM user_memories WHERE id = $1 AND user_id = $2', [toDelete[i].id, req.user.id]); } } var name = original_snippet.substring(0, 60).replace(/\n/g, ' ') + '...'; var content = 'ORIGINAL: ' + original_snippet.substring(0, 2000) + '\nCORRECTED TO: ' + corrected_snippet.substring(0, 2000); await db.run( 'INSERT INTO user_memories (user_id, category, name, content) VALUES ($1,$2,$3,$4)', [req.user.id, cat, name, content] ); res.json({ success: true }); } catch (e) { logger.error('POST /memories/correction', e.message); res.status(500).json({ error: e.message }); } }); module.exports = router;