documents added for the code generation context
This commit is contained in:
commit
f3e58dd50a
944
Markdown_Viewer.html
Normal file
944
Markdown_Viewer.html
Normal file
@ -0,0 +1,944 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Markdown Viewer</title>
|
||||
<!-- Marked.js for Markdown parsing -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<!-- Highlight.js for syntax highlighting -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
||||
<!-- DOMPurify for XSS protection -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.6/dist/purify.min.js"></script>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.5em;
|
||||
margin-bottom: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.header p {
|
||||
font-size: 1.1em;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
grid-template-columns: 400px 1fr;
|
||||
gap: 30px;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.panel {
|
||||
background: #f8f9fa;
|
||||
border-radius: 15px;
|
||||
padding: 25px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.panel h2 {
|
||||
color: #667eea;
|
||||
margin-bottom: 20px;
|
||||
font-size: 1.5em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
flex: 1;
|
||||
padding: 12px 20px;
|
||||
border: none;
|
||||
background: white;
|
||||
color: #667eea;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.tab-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.tab-btn.active {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tab-content.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
border: 3px dashed #667eea;
|
||||
border-radius: 15px;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.upload-area:hover {
|
||||
border-color: #764ba2;
|
||||
background: #f0f4ff;
|
||||
}
|
||||
|
||||
.upload-area.dragover {
|
||||
border-color: #764ba2;
|
||||
background: #e8ecff;
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
.upload-icon {
|
||||
font-size: 3em;
|
||||
margin-bottom: 15px;
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
.upload-area p {
|
||||
color: #666;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
#fileInput {
|
||||
display: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
min-height: 300px;
|
||||
padding: 15px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 10px;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 0.95em;
|
||||
resize: vertical;
|
||||
transition: border-color 0.3s ease;
|
||||
background: white;
|
||||
}
|
||||
|
||||
textarea:focus {
|
||||
outline: none;
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
margin-top: 15px;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border-radius: 10px;
|
||||
font-size: 1.1em;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.options-group {
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
border: 2px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.options-group h3 {
|
||||
font-size: 1em;
|
||||
color: #667eea;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.checkbox-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.checkbox-group label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.checkbox-group input[type="checkbox"] {
|
||||
cursor: pointer;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
#markdownOutput {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
padding: 30px;
|
||||
min-height: 500px;
|
||||
overflow-y: auto;
|
||||
max-height: calc(100vh - 250px);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.export-controls {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.export-btn {
|
||||
min-width: 100px;
|
||||
padding: 10px 15px;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border-radius: 10px;
|
||||
font-size: 0.9em;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
.export-btn:hover {
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
|
||||
}
|
||||
|
||||
.export-btn.success {
|
||||
background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 1.2em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.placeholder-icon {
|
||||
font-size: 4em;
|
||||
margin-bottom: 15px;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.error {
|
||||
background: #fee;
|
||||
border: 2px solid #fcc;
|
||||
color: #c33;
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.success {
|
||||
background: #efe;
|
||||
border: 2px solid #cfc;
|
||||
color: #3c3;
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
/* Markdown Styling */
|
||||
#markdownOutput.rendered {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #24292e;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered h1 {
|
||||
font-size: 2em;
|
||||
border-bottom: 2px solid #eaecef;
|
||||
padding-bottom: 0.3em;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered h2 {
|
||||
font-size: 1.5em;
|
||||
border-bottom: 1px solid #eaecef;
|
||||
padding-bottom: 0.3em;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered h3 {
|
||||
font-size: 1.25em;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered h4,
|
||||
#markdownOutput.rendered h5,
|
||||
#markdownOutput.rendered h6 {
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered ul,
|
||||
#markdownOutput.rendered ol {
|
||||
padding-left: 2em;
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered li {
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered blockquote {
|
||||
padding: 0 1em;
|
||||
color: #6a737d;
|
||||
border-left: 0.25em solid #dfe2e5;
|
||||
margin: 0 0 16px 0;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered code {
|
||||
padding: 0.2em 0.4em;
|
||||
margin: 0;
|
||||
font-size: 85%;
|
||||
background-color: rgba(27, 31, 35, 0.05);
|
||||
border-radius: 6px;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered pre {
|
||||
padding: 16px;
|
||||
overflow: auto;
|
||||
font-size: 85%;
|
||||
line-height: 1.45;
|
||||
background-color: #f6f8fa;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered pre code {
|
||||
display: block;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: visible;
|
||||
line-height: inherit;
|
||||
word-wrap: normal;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered table th,
|
||||
#markdownOutput.rendered table td {
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered table th {
|
||||
font-weight: 600;
|
||||
background-color: #f6f8fa;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered table tr {
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #c6cbd1;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered table tr:nth-child(2n) {
|
||||
background-color: #f6f8fa;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered a {
|
||||
color: #0366d6;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
#markdownOutput.rendered hr {
|
||||
height: 0.25em;
|
||||
padding: 0;
|
||||
margin: 24px 0;
|
||||
background-color: #e1e4e8;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Dark theme for code blocks */
|
||||
#markdownOutput.rendered pre code.hljs {
|
||||
background: #2d2d2d;
|
||||
color: #f8f8f2;
|
||||
padding: 16px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
@media print {
|
||||
body {
|
||||
background: white;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
box-shadow: none;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.panel:first-child,
|
||||
.export-controls {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#markdownOutput {
|
||||
max-height: none;
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 968px) {
|
||||
.content {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.export-controls {
|
||||
position: relative;
|
||||
top: 0;
|
||||
right: 0;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>📝 Markdown Viewer</h1>
|
||||
<p>Upload a file or paste your Markdown to see beautiful rendered output</p>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="panel">
|
||||
<h2>📄 Input</h2>
|
||||
|
||||
<div class="tabs">
|
||||
<button class="tab-btn active" onclick="switchTab('paste')">Paste Markdown</button>
|
||||
<button class="tab-btn" onclick="switchTab('upload')">Upload File</button>
|
||||
</div>
|
||||
|
||||
<div id="pasteTab" class="tab-content active">
|
||||
<textarea id="markdownCode" placeholder="Paste your Markdown content here...
|
||||
|
||||
Example:
|
||||
# Hello World
|
||||
|
||||
This is **bold** and this is *italic*.
|
||||
|
||||
- Item 1
|
||||
- Item 2
|
||||
- Item 3
|
||||
|
||||
```javascript
|
||||
console.log('Hello, World!');
|
||||
```
|
||||
"></textarea>
|
||||
<button class="btn" onclick="renderMarkdown()">🎨 Render Markdown</button>
|
||||
</div>
|
||||
|
||||
<div id="uploadTab" class="tab-content">
|
||||
<div class="upload-area" id="uploadArea" onclick="document.getElementById('fileInput').click()">
|
||||
<div class="upload-icon">📁</div>
|
||||
<p><strong>Click to upload</strong> or drag and drop</p>
|
||||
<p style="font-size: 0.9em; margin-top: 10px; opacity: 0.7;">Supports .md, .markdown, .txt files</p>
|
||||
</div>
|
||||
<input type="file" id="fileInput" accept=".md,.markdown,.txt" onchange="handleFile(event)">
|
||||
</div>
|
||||
|
||||
<div class="options-group">
|
||||
<h3>⚙️ Options</h3>
|
||||
<div class="checkbox-group">
|
||||
<label>
|
||||
<input type="checkbox" id="enableGFM" checked>
|
||||
GitHub Flavored Markdown (GFM)
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" id="enableBreaks" checked>
|
||||
Line breaks
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" id="enableTables" checked>
|
||||
Tables support
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" id="enableSanitize" checked>
|
||||
Sanitize HTML (Security)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="message"></div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<h2>👁️ Preview</h2>
|
||||
<div id="markdownOutput">
|
||||
<div class="placeholder">
|
||||
<div class="placeholder-icon">📄</div>
|
||||
<p>Your rendered Markdown will appear here</p>
|
||||
</div>
|
||||
<div class="export-controls" id="exportControls">
|
||||
<button class="export-btn success" onclick="exportAsHTML()" title="Export as HTML">💾 HTML</button>
|
||||
<button class="export-btn" onclick="exportAsPDF()" title="Print as PDF">🖨️ PDF</button>
|
||||
<button class="export-btn" onclick="copyToClipboard()" title="Copy HTML to Clipboard">📋 Copy</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let currentTab = 'paste';
|
||||
|
||||
// Configure marked with options
|
||||
function getMarkedOptions() {
|
||||
return {
|
||||
gfm: document.getElementById('enableGFM').checked,
|
||||
breaks: document.getElementById('enableBreaks').checked,
|
||||
tables: document.getElementById('enableTables').checked,
|
||||
highlight: function(code, lang) {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return hljs.highlight(code, { language: lang }).value;
|
||||
} catch (err) {
|
||||
console.error('Highlight error:', err);
|
||||
}
|
||||
}
|
||||
return hljs.highlightAuto(code).value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function switchTab(tab) {
|
||||
currentTab = tab;
|
||||
document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
|
||||
document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
|
||||
|
||||
if (tab === 'paste') {
|
||||
document.querySelector('.tab-btn:first-child').classList.add('active');
|
||||
document.getElementById('pasteTab').classList.add('active');
|
||||
} else {
|
||||
document.querySelector('.tab-btn:last-child').classList.add('active');
|
||||
document.getElementById('uploadTab').classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
function showMessage(message, type) {
|
||||
const messageDiv = document.getElementById('message');
|
||||
messageDiv.innerHTML = `<div class="${type}">${message}</div>`;
|
||||
setTimeout(() => {
|
||||
messageDiv.innerHTML = '';
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function renderMarkdown() {
|
||||
const code = document.getElementById('markdownCode').value;
|
||||
const output = document.getElementById('markdownOutput');
|
||||
const exportControls = document.getElementById('exportControls');
|
||||
|
||||
if (!code.trim()) {
|
||||
showMessage('Please provide Markdown content', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Configure marked with current options
|
||||
marked.setOptions(getMarkedOptions());
|
||||
|
||||
// Parse markdown
|
||||
let html = marked.parse(code);
|
||||
|
||||
// Sanitize if enabled
|
||||
if (document.getElementById('enableSanitize').checked) {
|
||||
html = DOMPurify.sanitize(html, {
|
||||
ALLOWED_TAGS: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'br', 'strong', 'em', 'u', 's', 'ul', 'ol', 'li', 'a', 'img', 'code', 'pre', 'blockquote', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'hr', 'div', 'span'],
|
||||
ALLOWED_ATTR: ['href', 'src', 'alt', 'title', 'class', 'style', 'target', 'rel']
|
||||
});
|
||||
}
|
||||
|
||||
// Render to output
|
||||
output.innerHTML = html;
|
||||
output.classList.add('rendered');
|
||||
|
||||
// Highlight code blocks
|
||||
output.querySelectorAll('pre code').forEach((block) => {
|
||||
hljs.highlightElement(block);
|
||||
});
|
||||
|
||||
// Show export controls
|
||||
const controlsDiv = document.createElement('div');
|
||||
controlsDiv.className = 'export-controls';
|
||||
controlsDiv.id = 'exportControls';
|
||||
controlsDiv.style.display = 'flex';
|
||||
controlsDiv.innerHTML = `
|
||||
<button class="export-btn success" onclick="exportAsHTML()" title="Export as HTML">💾 HTML</button>
|
||||
<button class="export-btn" onclick="exportAsPDF()" title="Print as PDF">🖨️ PDF</button>
|
||||
<button class="export-btn" onclick="copyToClipboard()" title="Copy HTML to Clipboard">📋 Copy</button>
|
||||
`;
|
||||
|
||||
// Remove old controls if exist
|
||||
const oldControls = output.querySelector('.export-controls');
|
||||
if (oldControls) {
|
||||
oldControls.remove();
|
||||
}
|
||||
|
||||
output.appendChild(controlsDiv);
|
||||
|
||||
showMessage('✅ Markdown rendered successfully!', 'success');
|
||||
} catch (error) {
|
||||
output.innerHTML = '<div class="placeholder"><div class="placeholder-icon">❌</div><p>Failed to render Markdown</p></div>';
|
||||
showMessage('❌ Error: ' + error.message, 'error');
|
||||
console.error('Render error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function handleFile(event) {
|
||||
const file = event.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
const content = e.target.result;
|
||||
document.getElementById('markdownCode').value = content;
|
||||
renderMarkdown();
|
||||
showMessage('✅ File loaded: ' + file.name, 'success');
|
||||
};
|
||||
reader.onerror = function() {
|
||||
showMessage('❌ Error reading file', 'error');
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
|
||||
function exportAsHTML() {
|
||||
const output = document.getElementById('markdownOutput');
|
||||
const html = output.innerHTML;
|
||||
|
||||
if (!html || html.includes('placeholder')) {
|
||||
showMessage('❌ No content to export', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Create complete HTML document
|
||||
const fullHTML = `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Markdown Export</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css">
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #24292e;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
${getMarkdownStyles()}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${html}
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
// Create blob and download
|
||||
const blob = new Blob([fullHTML], { type: 'text/html;charset=utf-8' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.download = `markdown-export-${Date.now()}.html`;
|
||||
link.href = url;
|
||||
link.click();
|
||||
|
||||
// Cleanup
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
showMessage('✅ HTML exported successfully!', 'success');
|
||||
} catch (error) {
|
||||
showMessage('❌ Error: ' + error.message, 'error');
|
||||
console.error('Export error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function exportAsPDF() {
|
||||
showMessage('📄 Opening print dialog... Choose "Save as PDF" from the printer options', 'success');
|
||||
setTimeout(() => {
|
||||
window.print();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function copyToClipboard() {
|
||||
const output = document.getElementById('markdownOutput');
|
||||
const html = output.innerHTML;
|
||||
|
||||
if (!html || html.includes('placeholder')) {
|
||||
showMessage('❌ No content to copy', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Copy to clipboard
|
||||
navigator.clipboard.writeText(html).then(() => {
|
||||
showMessage('✅ HTML copied to clipboard!', 'success');
|
||||
}).catch(err => {
|
||||
// Fallback for older browsers
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.value = html;
|
||||
document.body.appendChild(textArea);
|
||||
textArea.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(textArea);
|
||||
showMessage('✅ HTML copied to clipboard!', 'success');
|
||||
});
|
||||
} catch (error) {
|
||||
showMessage('❌ Error: ' + error.message, 'error');
|
||||
console.error('Copy error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function getMarkdownStyles() {
|
||||
return `
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
border-bottom: 2px solid #eaecef;
|
||||
padding-bottom: 0.3em;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.5em;
|
||||
border-bottom: 1px solid #eaecef;
|
||||
padding-bottom: 0.3em;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.25em;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
ul, ol {
|
||||
padding-left: 2em;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
blockquote {
|
||||
padding: 0 1em;
|
||||
color: #6a737d;
|
||||
border-left: 0.25em solid #dfe2e5;
|
||||
margin: 0 0 16px 0;
|
||||
}
|
||||
code {
|
||||
padding: 0.2em 0.4em;
|
||||
margin: 0;
|
||||
font-size: 85%;
|
||||
background-color: rgba(27, 31, 35, 0.05);
|
||||
border-radius: 6px;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
}
|
||||
pre {
|
||||
padding: 16px;
|
||||
overflow: auto;
|
||||
font-size: 85%;
|
||||
line-height: 1.45;
|
||||
background-color: #2d2d2d;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
pre code {
|
||||
display: block;
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
color: #f8f8f2;
|
||||
}
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
table th, table td {
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
}
|
||||
table th {
|
||||
font-weight: 600;
|
||||
background-color: #f6f8fa;
|
||||
}
|
||||
a {
|
||||
color: #0366d6;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
margin: 16px 0;
|
||||
}
|
||||
hr {
|
||||
height: 0.25em;
|
||||
padding: 0;
|
||||
margin: 24px 0;
|
||||
background-color: #e1e4e8;
|
||||
border: 0;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
// Drag and drop support
|
||||
const uploadArea = document.getElementById('uploadArea');
|
||||
|
||||
uploadArea.addEventListener('dragover', (e) => {
|
||||
e.preventDefault();
|
||||
uploadArea.classList.add('dragover');
|
||||
});
|
||||
|
||||
uploadArea.addEventListener('dragleave', () => {
|
||||
uploadArea.classList.remove('dragover');
|
||||
});
|
||||
|
||||
uploadArea.addEventListener('drop', (e) => {
|
||||
e.preventDefault();
|
||||
uploadArea.classList.remove('dragover');
|
||||
|
||||
const file = e.dataTransfer.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(event) {
|
||||
const content = event.target.result;
|
||||
document.getElementById('markdownCode').value = content;
|
||||
renderMarkdown();
|
||||
showMessage('✅ File loaded: ' + file.name, 'success');
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
});
|
||||
|
||||
// Keyboard shortcut
|
||||
document.getElementById('markdownCode').addEventListener('keydown', function(e) {
|
||||
if (e.ctrlKey && e.key === 'Enter') {
|
||||
renderMarkdown();
|
||||
}
|
||||
});
|
||||
|
||||
// Auto-render on option change
|
||||
document.querySelectorAll('.checkbox-group input').forEach(checkbox => {
|
||||
checkbox.addEventListener('change', () => {
|
||||
const code = document.getElementById('markdownCode').value;
|
||||
if (code.trim()) {
|
||||
renderMarkdown();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
1053
Mermaid_Selector.html
Normal file
1053
Mermaid_Selector.html
Normal file
File diff suppressed because it is too large
Load Diff
35
docs/context/business_logic_flows.md
Normal file
35
docs/context/business_logic_flows.md
Normal file
@ -0,0 +1,35 @@
|
||||
# IamBilly Backend: Business Logic Flows
|
||||
|
||||
Based on the documentation at `http://34.111.248.204/`, the system consists of 9 core flows.
|
||||
|
||||
## Flow 1: Surgeon Records Dictation
|
||||
- **Patient Search:** Surgeon searches via MRN or Name.
|
||||
- **Failures:** If EMR connectivity fails, system retries (1s, 4s, 16s backoff). If still failing, cached data (<24h) is used or manual entry is required.
|
||||
- **Audio Capture:** Recorded locally on mobile, encrypted with AES-256.
|
||||
- **Connectivity:** Auto-uploads via TLS 1.3 when internet is available.
|
||||
|
||||
## Flow 2: AI Processing Pipeline (System)
|
||||
- **Transcription (Whisper):** Converts audio to text using medical vocabulary.
|
||||
- **Entity Extraction:** NLP extracts Diagnoses, Procedures, and Anatomy.
|
||||
- **Code Mapping:** AI maps to ICD-10 and CPT codes with modifiers.
|
||||
|
||||
## Flow 3: Surgeon Status Check
|
||||
- Surgeon monitors claim progress through a "Today's Cases" dashboard.
|
||||
|
||||
## Flow 4: Biller Review & Approval
|
||||
- **Interface:** Side-by-side view (Transcript vs. Coded Claim).
|
||||
- **Mandatory HR:** Human review is required before approval. AI-suggested fields are highlighted.
|
||||
|
||||
## Flow 5: Export & Revocation
|
||||
- **5a (Export):** Claims are pushed to Athena or EMR via API or generated as CMS-1500 PDF.
|
||||
- **5b (Revoke):** Supervisors can revoke approved status only if not yet exported.
|
||||
|
||||
## Flow 6: Rejection Handling
|
||||
- Claims rejected by billers come back to the Biller queue with specific reasons for manual correction.
|
||||
|
||||
## Flow 7 & 8: Management & Administration
|
||||
- **Supervisor:** Operational oversight (efficiency, accuracy).
|
||||
- **Admin:** System health monitoring, audit log reviews, and MFA management.
|
||||
|
||||
## Flow 9: Security Safeguards
|
||||
- Session timeouts (15 mins), MFA requirements, and persistent audit logs.
|
||||
17
docs/context/clinical_context.md
Normal file
17
docs/context/clinical_context.md
Normal file
@ -0,0 +1,17 @@
|
||||
# IamBilly Backend: Clinical Context (Spine Surgery)
|
||||
|
||||
The MVP is focused on high-volume spine surgery procedures.
|
||||
|
||||
## Procedure Templates
|
||||
The system supports 6 core spine templates, with a focus on:
|
||||
1. **ACDF Single Level** (Anterior Cervical Discectomy and Fusion)
|
||||
2. **Lumbar Fusion**
|
||||
|
||||
These templates pre-load standard CPT/ICD code pairs, which the surgeon can then modify via dictation if deviations occurred during the surgery.
|
||||
|
||||
## Clinical Entities
|
||||
The extraction layer is optimized for:
|
||||
- **Diagnoses:** ICD-10 codes.
|
||||
- **Procedures:** CPT codes + Modifiers (-59, -LT/RT, -51).
|
||||
- **Laterality:** Left, Right, Bilateral.
|
||||
- **Anatomy:** Specific spinal levels (e.g., C3-C4, L4-L5).
|
||||
19
docs/context/state_machine_and_badging.md
Normal file
19
docs/context/state_machine_and_badging.md
Normal file
@ -0,0 +1,19 @@
|
||||
# IamBilly Backend: State Machine & AI Confidence Logic
|
||||
|
||||
## Claim State Machine
|
||||
Claims must transition through the following 7 states:
|
||||
|
||||
1. **RECORDED:** Audio captured on mobile, upload confirmed.
|
||||
2. **TRANSCRIBING:** AI engine (Whisper) is converting audio to text.
|
||||
3. **CODING:** NLP engine is extracting entities and mapping ICD/CPT codes.
|
||||
4. **READY FOR REVIEW:** AI processing complete; sitting in Biller's inbox.
|
||||
5. **APPROVED:** Human biller/supervisor has verified the claim data.
|
||||
6. **REJECTED:** Human biller rejected the claim (requires reason code).
|
||||
7. **EXPORTED:** Claim successfully pushed to EMR or PDF generated. Final state.
|
||||
|
||||
## AI Confidence Logic (Color Coding)
|
||||
The processing layer must assign a confidence score to each extracted item:
|
||||
|
||||
- 🟢 **Green (>90%):** High confidence. Visual indicator for "Fast-Track" approval.
|
||||
- 🟠 **Orange (70-90%):** Moderate confidence. Triggers a mandatory review highlight for the biller.
|
||||
- 🔴 **Red (<70%):** Low confidence. System must provide the top 3 alternative mapping suggestions if confidence is between 70-80%, otherwise requires manual entry from scratch.
|
||||
17
docs/context/technical_specs.md
Normal file
17
docs/context/technical_specs.md
Normal file
@ -0,0 +1,17 @@
|
||||
# IamBilly Backend: Technical Context & Specifications
|
||||
|
||||
## Security & Encryption
|
||||
- **At Rest:** All PHI and Audio files must be encrypted with **AES-256 GCM**.
|
||||
- **In Transit:** All API communication and file uploads must use **TLS 1.3**.
|
||||
- **Audit Logs:** Immutable audit trail records for 7 years (per HIPAA).
|
||||
|
||||
## Connectivity & Retries
|
||||
- **EMR Integration:** 3 retry attempts for connectivity (exponential backoff: 1s, 4s, 16s).
|
||||
- **Athena/EMR Export:** 3 retry attempts for data push if the downstream API is unavailable.
|
||||
- **Caching:**
|
||||
- Patient data cached for 24 hours to mitigate EMR downtime.
|
||||
- Clinical documents cached for 30 days for cross-session reference.
|
||||
|
||||
## Identity Management
|
||||
- 15-minute global session idle timeout.
|
||||
- Mandatory Multi-Factor Authentication (MFA) for Administrative and Supervisor roles.
|
||||
123
project_structure.md
Normal file
123
project_structure.md
Normal file
@ -0,0 +1,123 @@
|
||||
### Technology Stack
|
||||
- **Framework:** FastAPI (Python)
|
||||
- **Database:** PostgreSQL + pgvector
|
||||
- **Cache:** Redis
|
||||
- **Task Queue:** Celery/RabbitMQ (for async STT and AI processing)
|
||||
- **AI Engines:** Whisper (Self-hosted), Llama/Mistral (Self-hosted)
|
||||
|
||||
---
|
||||
|
||||
## Production Readiness Overview
|
||||
This structure is built to **Production Grade** standards for healthcare applications:
|
||||
- **Scalability:** The Monolithic Modular approach allows modules to be extracted into microservices if needed, while maintaining shared logic in `shared/`.
|
||||
- **Security:** Built-in layers for JWT OAuth2, AES-256 encryption, and HIPAA-compliant data masking.
|
||||
- **Observability:** Centralized JSON logging and audit trails in `shared/utils/hipaa_logger.py`.
|
||||
- **Reliability:** Async DB sessions and background task workers (Celery) prevent request blocking during heavy AI processing.
|
||||
- **Maintainability:** Clear separation of concerns mapping directly to business domains (Claim, Billing, Patient).
|
||||
|
||||
---
|
||||
|
||||
## 1. Directory Tree Overview
|
||||
|
||||
```text
|
||||
iam_billy_backend/
|
||||
├── app/ # Main Application Package
|
||||
│ ├── main.py # App entry point & middleware
|
||||
│ ├── api/ # API Experience Layer
|
||||
│ │ ├── dependencies.py # Global FastAPI dependencies
|
||||
│ │ └── v1/ # Versioned API routes
|
||||
│ │ └── api.py # Main router inclusion
|
||||
│ ├── core/ # Global System Core
|
||||
│ │ ├── config.py # Settings (Pydantic)
|
||||
│ │ ├── security.py # Auth (JWT/OAuth2) logic
|
||||
│ │ └── exceptions.py # Global error handlers
|
||||
│ ├── database/ # Data Access Layer
|
||||
│ │ ├── base.py # SQLAlchemy model registry
|
||||
│ │ ├── session.py # DB Engine & Session factory
|
||||
│ │ └── migrations/ # Alembic migration scripts
|
||||
│ │ ├── env.py
|
||||
│ │ ├── script.py.mako
|
||||
│ │ └── versions/ # Individual migration files
|
||||
│ ├── modules/ # Domain-Driven Modules (Processing Layer)
|
||||
│ │ ├── auth/
|
||||
│ │ ├── patient/
|
||||
│ │ ├── audio/
|
||||
│ │ ├── ai_service/
|
||||
│ │ ├── billing/
|
||||
│ │ ├── claim/
|
||||
│ │ └── integration/ # EMR Adapter Implementations
|
||||
│ ├── shared/ # Cross-Module Resources
|
||||
│ │ ├── models/ # Shared DB Mixins
|
||||
│ │ ├── schemas/ # Generic Pydantic models (Pagination, Error)
|
||||
│ │ └── utils/ # Global Utilities
|
||||
│ │ ├── hipaa_logger.py # HIPAA-compliant JSON logging
|
||||
│ │ ├── encryptor.py # AES-256 Utility
|
||||
│ │ └── date_helpers.py # TZ-aware time logic
|
||||
│ └── ai_layer/ # AI Infrastructure (Local Inference)
|
||||
│ ├── models/ # Model loading scripts
|
||||
│ ├── rag/ # Vector store & RAG pipelines
|
||||
│ └── inference/ # Local Whisper/LLM runners
|
||||
├── scripts/ # Operational Scripts (Data Migration, ETL)
|
||||
├── tests/ # Pytest Suite
|
||||
├── alembic.ini # Migration config
|
||||
├── docker-compose.yml # Local Dev Orchestration
|
||||
├── requirements.txt # Dependency list
|
||||
└── README.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Granular Module Breakdown
|
||||
|
||||
Every domain module (`app/modules/<module>/`) follows this structure:
|
||||
|
||||
### `models.py`
|
||||
Defines SQLAlchemy ORM models.
|
||||
- *Example (Claim):* `Claim`, `ClaimHistory`, `AuditLog`.
|
||||
|
||||
### `schemas.py`
|
||||
Defines Pydantic models for request validation and response serialization.
|
||||
- *Example (Patient):* `PatientCreate`, `PatientPublic`, `PatientSearch`.
|
||||
|
||||
### `services/`
|
||||
Contains the business logic decoupled from the API layer.
|
||||
- `logic.py`: Primary business rules.
|
||||
- `validators.py`: Domain-specific validation logic.
|
||||
|
||||
### `routers/`
|
||||
FastAPI route definitions.
|
||||
- `endpoints.py`: HTTP methods (GET, POST, etc.) and payload handling.
|
||||
|
||||
### `tasks/`
|
||||
Celery background tasks.
|
||||
- `worker.py`: Async task definitions for the specific module.
|
||||
|
||||
---
|
||||
|
||||
## 3. Specialized Layouts
|
||||
|
||||
### **Migrations (`app/database/migrations/`)**
|
||||
- `versions/`: Auto-generated migration files reflecting schema changes.
|
||||
- `env.py`: Connects Alembic to the FastAPI application metadata.
|
||||
|
||||
### **Utilities (`app/shared/utils/`)**
|
||||
- `hipaa_logger.py`: Custom logging to ensure PHI isn't leaked in logs while satisfying audit trail requirements.
|
||||
- `encryptor.py`: Standardized AES-256 GCM logic for encrypting audio files at rest.
|
||||
- `emr_client.py`: Base HTTP client session for integration adapters.
|
||||
|
||||
### **AI Layer (`app/ai_layer/`)**
|
||||
- `inference/whisper_runner.py`: Logic to feed audio blobs to the local Whisper engine.
|
||||
- `rag/vector_indexer.py`: Logic to ingest PDF manuals/cheat-sheets into `pgvector`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Key Implementation Files
|
||||
|
||||
- **`app/main.py`**: Initializes FastAPI, adds CORS, mounts `v1` router, and sets up startup/shutdown events (DB connection, Redis init).
|
||||
- **`app/core/config.py`**: Uses `pydantic-settings` to load `.env` variables for Database URL, Redis URL, JWT Secret, and AI model paths.
|
||||
- **`requirements.txt`**:
|
||||
- `fastapi`, `uvicorn`, `sqlalchemy[asyncio]`, `asyncpg`
|
||||
- `pydantic[email]`, `pydantic-settings`
|
||||
- `alembic`, `celery`, `redis`
|
||||
- `cryptography`, `python-jose[cryptography]`
|
||||
- `pgv-sdk` (for vector search)
|
||||
90
project_structure_detailed.md
Normal file
90
project_structure_detailed.md
Normal file
@ -0,0 +1,90 @@
|
||||
# Detailed File-Level Project Structure: IamBilly Backend
|
||||
|
||||
This document provides an exhaustive file-level breakdown of the IamBilly backend, adhering to the monolithic modular pattern and the stack requirements (FastAPI, PostgreSQL, Redis, AI Layer).
|
||||
|
||||
---
|
||||
|
||||
## 1. Global Core Structure (`app/`)
|
||||
|
||||
### `app/core/`
|
||||
- `config.py`: Centralized environment variable management (Pydantic Settings).
|
||||
- `security.py`: JWT token generation, password hashing, and OAuth2 scopes.
|
||||
- `encryption.py`: AES-256 logic for at-rest storage of audio and PHI.
|
||||
- `logging.py`: HIPAA-compliant JSON logging with audit trail metadata.
|
||||
- `exceptions.py`: Custom HTTP exception handlers for global error responses.
|
||||
|
||||
### `app/api/`
|
||||
- `v1/api.py`: Main router that includes all module-level routers.
|
||||
- `dependencies.py`: Global FastAPI dependencies (e.g., `get_current_active_user`).
|
||||
|
||||
### `app/database/`
|
||||
- `base.py`: Import all SQLAlchemy models here for Alembic detection.
|
||||
- `session.py`: Database engine and async session factory setup.
|
||||
- `crud.py`: Common CRUD operations for shared entities.
|
||||
|
||||
---
|
||||
|
||||
## 2. Domain Modules (`app/modules/`)
|
||||
|
||||
Every module below follows this structure: `<module>/[models.py, schemas.py, service.py, router.py, tasks.py]`.
|
||||
|
||||
### `modules/auth/`
|
||||
- `models.py`: `User`, `Role`, `Permission` tables.
|
||||
- `schemas.py`: Login, Token, and User management schemas.
|
||||
- `service.py`: Authentication logic, role verification.
|
||||
- `router.py`: `/login`, `/refresh`, `/me` endpoints.
|
||||
|
||||
### `modules/patient/`
|
||||
- `models.py`: `Patient`, `PatientEMRMap`.
|
||||
- `schemas.py`: Patient search results and metadata.
|
||||
- `service.py`: Real-time Lookup logic (caching EMR results).
|
||||
- `router.py`: `/patients/search`, `/patients/{id}`.
|
||||
|
||||
### `modules/audio/`
|
||||
- `models.py`: `Recording`, `AudioSession`.
|
||||
- `schemas.py`: Upload validation and status updates.
|
||||
- `service.py`: Secure file handling, metadata extraction.
|
||||
- `router.py`: `/audio/upload`, `/audio/{id}/status`.
|
||||
- `tasks.py`: Background task to move files to encrypted object storage.
|
||||
|
||||
### `modules/ai_service/`
|
||||
- `service.py`: Orchestrator for the "Voice-to-Claim" pipeline.
|
||||
- `extraction.py`: NLP logic for entity extraction (Diagnosis, Procedure, Laterality).
|
||||
- `transcription.py`: Integration with Whisper STT.
|
||||
- `tasks.py`: Celery worker for long-running STT/LLM inference.
|
||||
|
||||
### `modules/billing/`
|
||||
- `models.py`: `PayerRule`, `NCCIEdit`, `ModifierMap`.
|
||||
- `service.py`: Rules engine logic, optimization strategies for 10-20 spine procedures.
|
||||
- `rag_service.py`: Logic to query the `ai_layer` vector store for scrubbing.
|
||||
- `router.py`: `/billing/payer-rules`.
|
||||
|
||||
### `modules/claim/`
|
||||
- `models.py`: `Claim` (State Machine), `ClaimRevision`, `AuditTrail`.
|
||||
- `schemas.py`: Full CMS-1500 JSON representation.
|
||||
- `service.py`: Lifecycle management (Draft -> Human Review -> Exported).
|
||||
- `router.py`: `/claims/queue`, `/claims/{id}/approve`, `/claims/{id}/reject`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Infrastructure & Integration Layer
|
||||
|
||||
### `app/ai_layer/`
|
||||
- `models/`: Loader scripts for Llama/Mistral/Qwen models.
|
||||
- `rag/`: Vector DB initialization (pgvector), indexing policy docs/manuals.
|
||||
- `inference/`: `whisper_service.py` (STT extraction) and `llm_service.py` (Entity Extraction).
|
||||
|
||||
### `app/integration/`
|
||||
- `base_adapter.py`: Abstract base class for EMR integrations.
|
||||
- `epic_fhir.py`: Epic R4 FHIR client (Patient, Encounter, DocRef resources).
|
||||
- `athena_api.py`: Custom client for Athena Centricity.
|
||||
- `curemd_api.py`: CureMD REST client.
|
||||
|
||||
---
|
||||
|
||||
## 4. Root Config Files
|
||||
- `main.py`: App initialization, Middleware (CORS/HIPAA logging), and API Mounting.
|
||||
- `celery_app.py`: Celery configuration for async tasks.
|
||||
- `alembic.ini`: Database migration config.
|
||||
- `docker-compose.yml`: Definition for `api`, `worker`, `db`, `redis`.
|
||||
- `requirements.txt`: To include: `fastapi`, `sqlalchemy[asyncio]`, `pgv-sdk`, `pydantic-settings`, `celery`, `redis`, `python-multipart`, `cryptography`.
|
||||
1999
srs_document.md
Normal file
1999
srs_document.md
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user