pediatric-ai-scribe-v3/public/js/correctionTracker.js
Daniel Onyejesi 5f066bb760 v9: Major feature update — audio backup, SOAP save, Dragon memory, S3 docs, CI/CD, APK
Phase 1 — Critical Fixes:
- Fix SOAP instructions not clearing on Clear button
- Show transcription provider (AWS/OpenAI) in UI toast
- Fix silent transcription failures in dictation and SOAP modules
- Add IndexedDB audio backup system (24hr retention, retry from Settings)
- Prevent duplicate encounter saves with idempotency keys
- Add Save/Load/New bar to SOAP note generator

Phase 2 — Features:
- Dragon-like AI memory: auto-track user corrections, inject into prompts
- Per-section template categories (SOAP, HPI, well visit, sick visit)
- Bigger textarea for SOAP instructions
- S3 document upload/management (AWS S3, Backblaze B2, MinIO compatible)
- Faster transcription via lower bitrate recording (16kbps opus)

Phase 3 — APK & CI/CD:
- GitHub Actions: Docker build+push on version tags
- GitHub Actions: TWA APK build for Obtainium auto-updates
- Android TWA project with foreground service for background recording
- Enhanced PWA manifest with shortcuts and maskable icons
2026-03-28 21:08:32 +00:00

86 lines
2.9 KiB
JavaScript

// ============================================================
// CORRECTION TRACKER — Dragon-like AI learning from user edits
// Tracks when users edit AI-generated output and saves corrections
// so the AI can learn user preferences over time.
// ============================================================
(function() {
// Store original AI outputs per element
var _originals = {};
// Track an output element: store original text when AI generates it
window.trackAIOutput = function(elementId, originalText) {
if (!elementId || !originalText) return;
_originals[elementId] = originalText.trim();
};
// Save correction when user is done editing (call on save or blur)
window.saveCorrection = function(elementId, section) {
var original = _originals[elementId];
if (!original) return;
var el = document.getElementById(elementId);
if (!el) return;
var current = (el.innerText || el.textContent || '').trim();
if (!current || current === original) return;
// Only save if there's a meaningful difference (not just whitespace)
var origWords = original.split(/\s+/).length;
var currWords = current.split(/\s+/).length;
var wordDiff = Math.abs(origWords - currWords);
// Require at least some meaningful change
if (wordDiff < 2 && original.length > 100) {
// Check character-level difference
var charDiff = Math.abs(original.length - current.length);
if (charDiff < 20) return; // too minor
}
// Find the most significant changed section (not full text)
var origSnippet = extractDiffSnippet(original, current);
var corrSnippet = extractDiffSnippet(current, original);
if (!origSnippet || !corrSnippet) {
origSnippet = original.substring(0, 500);
corrSnippet = current.substring(0, 500);
}
fetch('/api/memories/correction', {
method: 'POST',
headers: getAuthHeaders(),
body: JSON.stringify({
section: section || 'encounter',
original_snippet: origSnippet,
corrected_snippet: corrSnippet
})
}).then(function(r) { return r.json(); })
.then(function(data) {
if (data.success && !data.skipped) {
console.log('[CorrectionTracker] Saved correction for', section);
}
}).catch(function() {});
// Clear so we don't re-save
delete _originals[elementId];
};
// Extract the most changed portion between two texts
function extractDiffSnippet(text1, text2) {
var lines1 = text1.split('\n');
var lines2 = text2.split('\n');
var changed = [];
var maxLen = Math.max(lines1.length, lines2.length);
for (var i = 0; i < maxLen; i++) {
var l1 = (lines1[i] || '').trim();
var l2 = (lines2[i] || '').trim();
if (l1 !== l2 && l1) {
changed.push(l1);
}
}
if (changed.length === 0) return null;
return changed.slice(0, 10).join('\n').substring(0, 1000);
}
console.log('Correction tracker loaded');
})();