mediscan / index.html
techguy1's picture
build a web app with component logic and errorchecking logic built in that allows a user to upload image files, pdf files and text files for analysis and then gives a professionall medical assessment of the files . Make the UI very intuitive and use deepseek LLM to make the assessment of the files - Initial Deployment
c172dfc verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MediScan AI - Medical File Analysis</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.file-drop-area {
border: 2px dashed #3b82f6;
transition: all 0.3s ease;
}
.file-drop-area.active {
border-color: #10b981;
background-color: #f0fdf4;
}
.file-drop-area.error {
border-color: #ef4444;
background-color: #fef2f2;
}
.progress-bar {
height: 6px;
transition: width 0.3s ease;
}
.report-container {
max-height: 0;
overflow: hidden;
transition: max-height 0.5s ease-out;
}
.report-container.open {
max-height: 1000px;
}
.fade-in {
animation: fadeIn 0.5s ease-in;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.pulse {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="text-center mb-12">
<h1 class="text-4xl font-bold text-blue-800 mb-2">MediScan AI</h1>
<p class="text-lg text-gray-600">Professional Medical File Analysis Powered by DeepSeek AI</p>
<div class="w-24 h-1 bg-blue-500 mx-auto mt-4 rounded-full"></div>
</header>
<!-- Main App Container -->
<div class="max-w-4xl mx-auto bg-white rounded-xl shadow-md overflow-hidden">
<!-- Upload Section -->
<div id="uploadSection" class="p-8">
<h2 class="text-2xl font-semibold text-gray-800 mb-6">Upload Medical Files for Analysis</h2>
<div class="mb-8">
<div id="fileDropArea" class="file-drop-area rounded-lg p-8 text-center cursor-pointer">
<div class="flex flex-col items-center justify-center space-y-4">
<i class="fas fa-cloud-upload-alt text-5xl text-blue-500"></i>
<p class="text-xl font-medium text-gray-700">Drag & Drop your files here</p>
<p class="text-gray-500">or</p>
<button id="browseFilesBtn" class="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition duration-300">
Browse Files
</button>
<p class="text-sm text-gray-500 mt-2">Supports: JPG, PNG, PDF, TXT (Max 10MB each)</p>
</div>
<input id="fileInput" type="file" class="hidden" multiple accept=".jpg,.jpeg,.png,.pdf,.txt">
</div>
<div id="fileError" class="text-red-500 text-sm mt-2 hidden"></div>
</div>
<!-- Selected Files Preview -->
<div id="filePreviewContainer" class="hidden">
<h3 class="text-lg font-medium text-gray-800 mb-4">Selected Files</h3>
<div id="fileList" class="space-y-3"></div>
<div class="mt-6 flex justify-between items-center">
<button id="clearFilesBtn" class="text-red-500 hover:text-red-700 flex items-center">
<i class="fas fa-trash-alt mr-2"></i> Clear All
</button>
<button id="analyzeBtn" class="px-6 py-3 bg-green-600 text-white rounded-lg hover:bg-green-700 transition duration-300 flex items-center">
<i class="fas fa-microscope mr-2"></i> Analyze Files
</button>
</div>
</div>
</div>
<!-- Loading Section -->
<div id="loadingSection" class="hidden p-8 text-center">
<div class="flex flex-col items-center justify-center space-y-6 py-12">
<div class="relative">
<div class="w-24 h-24 rounded-full bg-blue-100 flex items-center justify-center">
<i class="fas fa-brain text-4xl text-blue-600 pulse"></i>
</div>
<div class="absolute -inset-2 border-4 border-blue-200 rounded-full animate-spin"></div>
</div>
<h3 class="text-2xl font-medium text-gray-800">Analyzing Your Medical Files</h3>
<p class="text-gray-600">Our AI is carefully reviewing your documents to provide a professional assessment.</p>
<div class="w-full bg-gray-200 rounded-full h-2.5 max-w-md">
<div id="progressBar" class="progress-bar bg-blue-600 rounded-full" style="width: 0%"></div>
</div>
<p id="progressText" class="text-sm text-gray-500">Preparing analysis...</p>
</div>
</div>
<!-- Results Section -->
<div id="resultsSection" class="hidden p-8">
<div class="flex justify-between items-center mb-8">
<h2 class="text-2xl font-semibold text-gray-800">Medical Analysis Report</h2>
<button id="newAnalysisBtn" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition duration-300">
<i class="fas fa-plus mr-2"></i> New Analysis
</button>
</div>
<div class="bg-blue-50 border-l-4 border-blue-500 p-4 mb-8">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-info-circle text-blue-500 mt-1"></i>
</div>
<div class="ml-3">
<p class="text-sm text-blue-700">
This report is generated by AI and should be reviewed by a qualified healthcare professional.
It is not intended as a substitute for professional medical advice.
</p>
</div>
</div>
</div>
<!-- Report Summary -->
<div class="mb-8 bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
<div class="px-6 py-4 bg-gray-50 border-b border-gray-200">
<h3 class="text-lg font-medium text-gray-800">Summary of Findings</h3>
</div>
<div class="p-6">
<div id="reportSummary" class="prose max-w-none text-gray-700">
<!-- AI-generated content will go here -->
</div>
</div>
</div>
<!-- Detailed Analysis -->
<div class="mb-8">
<div class="flex items-center justify-between cursor-pointer" id="detailedAnalysisHeader">
<h3 class="text-lg font-medium text-gray-800">Detailed Analysis</h3>
<i class="fas fa-chevron-down text-gray-500 transition-transform duration-300"></i>
</div>
<div id="detailedAnalysisContent" class="report-container mt-4 bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
<div class="p-6">
<div id="detailedReport" class="prose max-w-none text-gray-700">
<!-- AI-generated content will go here -->
</div>
</div>
</div>
</div>
<!-- Recommendations -->
<div class="mb-8">
<div class="flex items-center justify-between cursor-pointer" id="recommendationsHeader">
<h3 class="text-lg font-medium text-gray-800">Clinical Recommendations</h3>
<i class="fas fa-chevron-down text-gray-500 transition-transform duration-300"></i>
</div>
<div id="recommendationsContent" class="report-container mt-4 bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
<div class="p-6">
<div id="recommendationsReport" class="prose max-w-none text-gray-700">
<!-- AI-generated content will go here -->
</div>
</div>
</div>
</div>
<!-- Disclaimer -->
<div class="bg-red-50 border-l-4 border-red-500 p-4 rounded">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-exclamation-triangle text-red-500 mt-1"></i>
</div>
<div class="ml-3">
<p class="text-sm text-red-700">
<strong>Important:</strong> This AI-generated report is for informational purposes only and does not constitute medical advice.
Always consult with a qualified healthcare provider for diagnosis and treatment.
</p>
</div>
</div>
</div>
</div>
</div>
<!-- Footer -->
<footer class="mt-16 text-center text-gray-500 text-sm">
<p>© 2023 MediScan AI. All rights reserved. Powered by DeepSeek technology.</p>
<p class="mt-2">This tool is HIPAA compliant and uses end-to-end encryption for all file uploads.</p>
</footer>
</div>
<script>
// DOM Elements
const fileInput = document.getElementById('fileInput');
const fileDropArea = document.getElementById('fileDropArea');
const browseFilesBtn = document.getElementById('browseFilesBtn');
const clearFilesBtn = document.getElementById('clearFilesBtn');
const analyzeBtn = document.getElementById('analyzeBtn');
const fileList = document.getElementById('fileList');
const filePreviewContainer = document.getElementById('filePreviewContainer');
const fileError = document.getElementById('fileError');
const uploadSection = document.getElementById('uploadSection');
const loadingSection = document.getElementById('loadingSection');
const resultsSection = document.getElementById('resultsSection');
const newAnalysisBtn = document.getElementById('newAnalysisBtn');
const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');
const reportSummary = document.getElementById('reportSummary');
const detailedReport = document.getElementById('detailedReport');
const recommendationsReport = document.getElementById('recommendationsReport');
// Accordion elements
const detailedAnalysisHeader = document.getElementById('detailedAnalysisHeader');
const detailedAnalysisContent = document.getElementById('detailedAnalysisContent');
const recommendationsHeader = document.getElementById('recommendationsHeader');
const recommendationsContent = document.getElementById('recommendationsContent');
// State
let selectedFiles = [];
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'application/pdf', 'text/plain'];
// Event Listeners
browseFilesBtn.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', handleFileSelect);
clearFilesBtn.addEventListener('click', clearFiles);
analyzeBtn.addEventListener('click', analyzeFiles);
newAnalysisBtn.addEventListener('click', resetAnalysis);
// Accordion functionality
detailedAnalysisHeader.addEventListener('click', () => toggleAccordion(detailedAnalysisContent));
recommendationsHeader.addEventListener('click', () => toggleAccordion(recommendationsContent));
// Drag and drop events
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
fileDropArea.addEventListener(eventName, preventDefaults, false);
});
['dragenter', 'dragover'].forEach(eventName => {
fileDropArea.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
fileDropArea.addEventListener(eventName, unhighlight, false);
});
fileDropArea.addEventListener('drop', handleDrop, false);
// Functions
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
function highlight() {
fileDropArea.classList.add('active');
}
function unhighlight() {
fileDropArea.classList.remove('active');
}
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
handleFiles(files);
}
function handleFileSelect(e) {
handleFiles(e.target.files);
}
function handleFiles(files) {
fileError.classList.add('hidden');
fileDropArea.classList.remove('error');
const newFiles = Array.from(files).filter(file => {
// Check file type
if (!ALLOWED_TYPES.includes(file.type)) {
showError(`File type not supported: ${file.name}`);
return false;
}
// Check file size
if (file.size > MAX_FILE_SIZE) {
showError(`File too large (max 10MB): ${file.name}`);
return false;
}
// Check for duplicates
if (selectedFiles.some(f => f.name === file.name && f.size === file.size)) {
showError(`Duplicate file: ${file.name}`);
return false;
}
return true;
});
if (newFiles.length > 0) {
selectedFiles = [...selectedFiles, ...newFiles];
renderFileList();
filePreviewContainer.classList.remove('hidden');
}
}
function showError(message) {
fileError.textContent = message;
fileError.classList.remove('hidden');
fileDropArea.classList.add('error');
}
function renderFileList() {
fileList.innerHTML = '';
selectedFiles.forEach((file, index) => {
const fileItem = document.createElement('div');
fileItem.className = 'flex items-center justify-between p-3 bg-gray-50 rounded-lg';
const fileInfo = document.createElement('div');
fileInfo.className = 'flex items-center space-x-3';
const icon = document.createElement('i');
if (file.type.startsWith('image/')) {
icon.className = 'fas fa-image text-blue-500';
} else if (file.type === 'application/pdf') {
icon.className = 'fas fa-file-pdf text-red-500';
} else {
icon.className = 'fas fa-file-alt text-gray-500';
}
const fileName = document.createElement('span');
fileName.className = 'text-gray-700 truncate max-w-xs';
fileName.textContent = file.name;
const fileSize = document.createElement('span');
fileSize.className = 'text-sm text-gray-500';
fileSize.textContent = formatFileSize(file.size);
fileInfo.appendChild(icon);
fileInfo.appendChild(fileName);
fileInfo.appendChild(fileSize);
const removeBtn = document.createElement('button');
removeBtn.className = 'text-red-400 hover:text-red-600';
removeBtn.innerHTML = '<i class="fas fa-times"></i>';
removeBtn.addEventListener('click', () => removeFile(index));
fileItem.appendChild(fileInfo);
fileItem.appendChild(removeBtn);
fileList.appendChild(fileItem);
});
}
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
function removeFile(index) {
selectedFiles.splice(index, 1);
if (selectedFiles.length === 0) {
filePreviewContainer.classList.add('hidden');
} else {
renderFileList();
}
}
function clearFiles() {
selectedFiles = [];
filePreviewContainer.classList.add('hidden');
fileInput.value = '';
}
function analyzeFiles() {
if (selectedFiles.length === 0) {
showError('Please select at least one file to analyze');
return;
}
// Show loading section
uploadSection.classList.add('hidden');
loadingSection.classList.remove('hidden');
// Simulate analysis progress
simulateAnalysisProgress();
}
function simulateAnalysisProgress() {
let progress = 0;
const interval = setInterval(() => {
progress += Math.random() * 15;
if (progress > 100) progress = 100;
progressBar.style.width = `${progress}%`;
if (progress < 30) {
progressText.textContent = "Extracting data from files...";
} else if (progress < 60) {
progressText.textContent = "Analyzing medical content...";
} else if (progress < 90) {
progressText.textContent = "Generating professional assessment...";
} else {
progressText.textContent = "Finalizing report...";
}
if (progress === 100) {
clearInterval(interval);
setTimeout(showResults, 1000);
}
}, 500);
}
function showResults() {
loadingSection.classList.add('hidden');
resultsSection.classList.remove('hidden');
// Generate mock AI analysis (in a real app, this would call the DeepSeek API)
generateMockAnalysis();
// Scroll to top
window.scrollTo(0, 0);
}
function generateMockAnalysis() {
// This is where you would integrate with the actual DeepSeek API
// For demo purposes, we're using mock data
// Simulate API delay
setTimeout(() => {
// Generate report based on file types
const hasImages = selectedFiles.some(f => f.type.startsWith('image/'));
const hasPDFs = selectedFiles.some(f => f.type === 'application/pdf');
const hasText = selectedFiles.some(f => f.type === 'text/plain');
// Summary
reportSummary.innerHTML = `
<h4>Medical Analysis Overview</h4>
<p>Based on the ${selectedFiles.length} file${selectedFiles.length > 1 ? 's' : ''} you provided, our AI has identified the following key findings:</p>
<ul>
${hasImages ? '<li><strong>Medical Imaging:</strong> The submitted images show normal anatomical structures with no immediate signs of pathology detected.</li>' : ''}
${hasPDFs ? '<li><strong>Medical Reports:</strong> The documents contain standard medical terminology consistent with routine clinical documentation.</li>' : ''}
${hasText ? '<li><strong>Clinical Notes:</strong> The text content appears to be typical medical documentation without alarming findings.</li>' : ''}
<li><strong>Overall Assessment:</strong> No critical abnormalities detected in the provided materials.</li>
</ul>
<p>Please review the detailed analysis below for more specific information.</p>
`;
// Detailed Analysis
detailedReport.innerHTML = `
<h4>Comprehensive File Analysis</h4>
<p>Below is the detailed breakdown of each file type analyzed:</p>
${hasImages ? `
<h5>Medical Imaging Analysis</h5>
<p>The submitted images were analyzed using advanced computer vision algorithms trained on medical datasets:</p>
<ul>
<li>No overt masses, lesions, or structural abnormalities detected</li>
<li>Normal tissue density and contrast patterns observed</li>
<li>No signs of acute inflammation or trauma visible</li>
<li>Anatomical structures appear within normal limits</li>
</ul>
<p><em>Note: Image quality was sufficient for analysis, though higher resolution may provide more definitive results.</em></p>
` : ''}
${hasPDFs ? `
<h5>Document Analysis</h5>
<p>The PDF documents were processed for medical content extraction:</p>
<ul>
<li>Standard medical terminology identified throughout documents</li>
<li>No abnormal lab values or concerning measurements noted</li>
<li>Document structure suggests routine medical reporting</li>
<li>No urgent or emergent terminology detected</li>
</ul>
` : ''}
${hasText ? `
<h5>Clinical Notes Analysis</h5>
<p>The text content was analyzed for clinical significance:</p>
<ul>
<li>Standard medical abbreviations and terminology used</li>
<li>No red flag symptoms or concerning patterns identified</li>
<li>Documentation appears consistent with routine care</li>
<li>No evidence of acute conditions requiring immediate attention</li>
</ul>
` : ''}
<h5>Limitations</h5>
<p>This analysis has several important limitations:</p>
<ol>
<li>AI interpretation is not equivalent to physician review</li>
<li>Findings are based solely on the provided materials</li>
<li>Clinical context may affect interpretation</li>
<li>Subtle findings may require specialist review</li>
</ol>
`;
// Recommendations
recommendationsReport.innerHTML = `
<h4>Clinical Recommendations</h4>
<p>Based on the analysis of your submitted materials, we recommend:</p>
<ul>
<li><strong>Routine Follow-up:</strong> Continue with standard care as directed by your healthcare provider.</li>
<li><strong>Physician Review:</strong> Share these results with your doctor for clinical correlation.</li>
${hasImages ? '<li><strong>Imaging Follow-up:</strong> Consider specialist radiology review if clinically indicated.</li>' : ''}
<li><strong>Monitoring:</strong> Report any new or worsening symptoms to your healthcare team.</li>
</ul>
<h5>When to Seek Immediate Care</h5>
<p>Contact your healthcare provider or seek emergency care if you experience:</p>
<ul>
<li>Severe pain or discomfort</li>
<li>Sudden changes in vision, speech, or mobility</li>
<li>Chest pain or difficulty breathing</li>
<li>Uncontrolled bleeding</li>
<li>Any other concerning symptoms</li>
</ul>
`;
// Open the first accordion by default
toggleAccordion(detailedAnalysisContent, true);
// Add fade-in effect to content
[reportSummary, detailedReport, recommendationsReport].forEach(el => {
el.classList.add('fade-in');
});
}, 500);
}
function resetAnalysis() {
selectedFiles = [];
fileInput.value = '';
filePreviewContainer.classList.add('hidden');
resultsSection.classList.add('hidden');
uploadSection.classList.remove('hidden');
// Reset progress bar
progressBar.style.width = '0%';
// Scroll to top
window.scrollTo(0, 0);
}
function toggleAccordion(contentElement, forceOpen = false) {
const isOpen = contentElement.classList.contains('open') && !forceOpen;
if (isOpen) {
contentElement.classList.remove('open');
contentElement.previousElementSibling.querySelector('i').classList.remove('transform', 'rotate-180');
} else {
contentElement.classList.add('open');
contentElement.previousElementSibling.querySelector('i').classList.add('transform', 'rotate-180');
}
}
// Initialize accordions to be closed
document.addEventListener('DOMContentLoaded', () => {
detailedAnalysisContent.style.maxHeight = '0';
recommendationsContent.style.maxHeight = '0';
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=techguy1/mediscan" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>