<!DOCTYPE html>
<html lang="en">
<head>
<title>Medical Research PDF Search</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bulma CSS Framework -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/bulma.min.css">
<style>
body { padding: 40px; }
.match { background-color: #ffdd57; font-weight: bold; padding: 2px 4px; border-radius: 4px; }
.box { padding: 20px; margin-bottom: 20px; }
.title { color: #363636; }
.notification { margin-top: 20px; }
.hero { margin-bottom: 40px; }
.search-results-section { margin-top: 40px; }
.search-input-container { margin-bottom: 20px; }
.document-card { margin-top: 20px; border-radius: 8px; }
</style>
</head>
<body>
<section class="hero is-primary">
<div class="hero-body">
<p class="title">
Medical Research PDF Search
</p>
<p class="subtitle">
Upload and search medical documents in real-time
</p>
</div>
</section>
<div class="container">
<!-- Upload Section -->
<div class="box">
<h2 class="title is-4">Upload PDF Document</h2>
<div class="field is-grouped">
<div class="control is-expanded">
<div class="file has-name is-fullwidth">
<label class="file-label">
<input class="file-input" type="file" id="pdfFile">
<span class="file-cta">
<span class="file-icon"><i class="fas fa-upload"></i></span>
<span class="file-label">Choose a PDF…</span>
</span>
<span class="file-name" id="fileName">No file selected</span>
</label>
</div>
</div>
<div class="control">
<button class="button is-primary" onclick="uploadPdf()">Upload</button>
</div>
</div>
<p id="uploadStatus" class="help"></p>
</div>
<!-- Search Section -->
<div class="box">
<h2 class="title is-4">Search Documents</h2>
<div class="field has-addons">
<div class="control is-expanded">
<input class="input" type="text" id="searchKeyword" placeholder="e.g., clinical trial, novel virus">
</div>
<div class="control">
<button class="button is-info" onclick="searchPdfs()">Search</button>
</div>
</div>
</div>
<!-- Search Results Section -->
<div class="search-results-section">
<div id="results" class="results-container"></div>
</div>
</div>
<script>
const fileInput = document.getElementById('pdfFile');
const fileNameSpan = document.getElementById('fileName');
fileInput.addEventListener('change', () => {
if (fileInput.files.length > 0) {
fileNameSpan.textContent = fileInput.files[0].name;
} else {
fileNameSpan.textContent = 'No file selected';
}
});
// Function to upload a PDF
async function uploadPdf() {
const file = fileInput.files[0];
const statusDiv = document.getElementById('uploadStatus');
if (!file) {
statusDiv.className = 'help is-danger';
statusDiv.innerText = 'No file selected.';
return;
}
statusDiv.innerText = 'Uploading...';
const formData = new FormData();
formData.append('pdf', file);
try {
const response = await fetch('/upload', {
method: 'POST',
body: formData
});
const result = await response.text();
statusDiv.className = 'help is-success';
statusDiv.innerText = result;
} catch (error) {
statusDiv.className = 'help is-danger';
statusDiv.innerText = 'Error uploading file.';
console.error(error);
}
}
// Function to search PDFs
async function searchPdfs() {
const keyword = document.getElementById('searchKeyword').value;
const resultsDiv = document.getElementById('results');
resultsDiv.innerHTML = '';
if (!keyword) {
resultsDiv.innerHTML = '<div class="notification is-danger">Please enter a keyword.</div>';
return;
}
try {
const response = await fetch(`/search?keyword=${encodeURIComponent(keyword)}`);
const pdfs = await response.json();
if (pdfs.length === 0) {
resultsDiv.innerHTML = '<div class="notification is-warning">No matches found.</div>';
} else {
pdfs.forEach(pdf => {
const pdfCard = document.createElement('div');
pdfCard.className = 'box document-card';
const pdfTitle = document.createElement('h4');
pdfTitle.className = 'title is-5';
pdfTitle.textContent = pdf.filename;
pdfCard.appendChild(pdfTitle);
const escapedKeyword = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const regex = new RegExp(escapedKeyword, 'gi');
const highlightedText = pdf.text.replace(regex, `<span class="match">${keyword}</span>`);
const preview = highlightedText.length > 800 ? highlightedText.substring(0, 800) + '...' : highlightedText;
const textContent = document.createElement('p');
textContent.className = 'is-size-7 has-text-grey-dark';
textContent.innerHTML = preview;
pdfCard.appendChild(textContent);
resultsDiv.appendChild(pdfCard);
});
}
} catch (error) {
resultsDiv.innerHTML = '<div class="notification is-danger">Error performing search.</div>';
console.error(error);
}
}
</script>
</body>
</html>
const PDFDocument = require('pdfkit');
const fs = require('fs');
function createSamplePdf() {
// Create a new PDF document instance
const doc = new PDFDocument();
// Pipe the PDF document to a write stream to save it to disk
doc.pipe(fs.createWriteStream('sample.pdf'));
// Add a title to the document
doc.fontSize(20).text('Medical Research Sample Document', {
align: 'center'
});
// Add a subtitle
doc.fontSize(14).text('\nPatient Case Study: Keyword Search Test', {
align: 'center'
});
// Add the main body of text with keywords
doc.moveDown();
doc.fontSize(12).text(
'This document is a sample case study for a research application. The patient, diagnosed with a **novel virus**, ' +
'exhibited a range of symptoms, including fever, persistent cough, and elevated inflammation markers. ' +
'The patient was enrolled in a clinical trial testing a new **treatment protocol**. ' +
'Following treatment, the patient’s inflammation levels returned to normal. The keyword **clinical trial** ' +
'is relevant to this case. Further research will focus on the **novel virus** and its variants.',
{
align: 'left',
indent: 20,
paragraphGap: 10
}
);
// Add a list of keywords for easy reference
doc.moveDown();
doc.fontSize(10).text('Keywords for Search:', { underline: true });
doc.fontSize(10).list(['novel virus', 'inflammation', 'clinical trial', 'treatment protocol', 'variants']);
// Finalize the PDF and end the stream
doc.end();
console.log('sample.pdf has been created.');
}
// Execute the function
createSamplePdf();
const PDFDocument = require('pdfkit');
const fs = require('fs');
const { faker } = require('@faker-js/faker');
function generateRealTimeMedicalPdf() {
const doc = new PDFDocument();
const fileName = 'real_time_clinical_data.pdf';
doc.pipe(fs.createWriteStream(fileName));
// Medical Research Title
doc.fontSize(20).text('Real-Time Clinical Trial Data', { align: 'center' });
doc.moveDown();
// Project details
doc.fontSize(12).text(`Project: Novel Respiratory Drug Trial`, { underline: true });
doc.text(`Trial ID: ${faker.string.alphanumeric(8).toUpperCase()}`);
doc.text(`Monitoring Date: ${new Date().toLocaleString()}`);
doc.moveDown();
// Simulate a real-time stream of patient monitoring data
doc.fontSize(10);
for (let i = 0; i < 50; i++) {
const patientID = `PT-${faker.string.numeric(5)}`;
const eventType = faker.helpers.arrayElement([
'Vital Sign Update',
'Adverse Event Reported',
'Medication Dispensed',
'Patient Interview',
]);
const eventTime = faker.date.recent({ days: 1 });
const bloodPressure = `${faker.number.int({ min: 100, max: 140 })}/${faker.number.int({ min: 60, max: 90 })}`;
const heartRate = faker.number.int({ min: 60, max: 100 });
const oxygenSaturation = faker.number.int({ min: 95, max: 99 });
const note = faker.lorem.sentences(1);
// Write a new line of data
doc.text(`[${eventTime.toLocaleTimeString()}] **${eventType}**: Patient ID ${patientID}`);
doc.text(` - Blood Pressure: ${bloodPressure}, Heart Rate: ${heartRate}, Oxygen Saturation: ${oxygenSaturation}%`);
doc.text(` - Notes: ${note}`);
doc.text('----------------------------------------------------');
}
// Finalize the PDF
doc.end();
console.log(`Successfully created a simulated real-time PDF: ${fileName}`);
}
// Execute the function
generateRealTimeMedicalPdf();
{
"name": "pdf-search-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@faker-js/faker": "^10.0.0",
"express": "^5.1.0",
"mongoose": "^8.18.1",
"multer": "^2.0.2",
"pdf-parse": "^1.1.1",
"pdfkit": "^0.17.2",
"socket.io": "^4.8.1"
}
}
const express = require('express');
const multer = require('multer');
const pdfParse = require('pdf-parse');
const path = require('path');
const fs = require('fs'); // Import the file system module
const app = express();
const port = 3000;
// An in-memory array to store the extracted PDF data
const pdfDocuments = [];
// Set up Multer to store uploaded files on the disk
const upload = multer({ dest: 'uploads/' });
// Ensure the 'uploads' directory exists
if (!fs.existsSync('uploads')) {
fs.mkdirSync('uploads');
}
app.use(express.static('public'));
// --- File Upload Endpoint ---
app.post('/upload', upload.single('pdf'), async (req, res) => {
if (!req.file || req.file.mimetype !== 'application/pdf') {
return res.status(400).send('Please upload a PDF file.');
}
try {
const filePath = req.file.path;
const dataBuffer = fs.readFileSync(filePath);
const data = await pdfParse(dataBuffer);
// Store the extracted text and original filename in memory
const newPdf = {
id: pdfDocuments.length + 1,
filename: req.file.originalname,
text: data.text
};
pdfDocuments.push(newPdf);
// Clean up the temporary file
fs.unlinkSync(filePath);
res.status(200).send('PDF uploaded and text extracted successfully.');
} catch (err) {
console.error('Error during PDF processing:', err);
res.status(500).send('Error processing PDF.');
}
});
// --- Real-time Search Endpoint ---
app.get('/search', (req, res) => {
const { keyword } = req.query;
if (!keyword) {
return res.status(400).send('Please provide a keyword to search.');
}
const results = pdfDocuments.filter(doc =>
doc.text.toLowerCase().includes(keyword.toLowerCase())
);
res.status(200).json(results);
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});