Files
FarmaFinder/scripts/generate_international_prior_art_search_pdf.mjs
T
Antoni Nuñez Romeu d68463548f
Run Tests on Branches / Detect Changes (push) Successful in 19s
Run Tests on Branches / Backend Tests (push) Successful in 2m46s
Run Tests on Branches / PIP Platform Tests (push) Has been skipped
Run Tests on Branches / Frontend Tests (push) Successful in 2m24s
Run Tests on Branches / Frontend Mobile Tests (push) Has been skipped
Run Tests on Branches / Parapharmacy API Tests (push) Has been skipped
Patentes internacionales + Forgot Pwd
2026-08-18 11:01:54 +02:00

199 lines
9.1 KiB
JavaScript

import fs from 'fs';
import path from 'path';
const outPath = path.resolve('Patentes/INTERNATIONAL_PRIOR_ART_SEARCH_FARMAFINDER_EN.pdf');
const sections = [
{ type: 'title', text: 'International Prior Art Search' },
{ type: 'subtitle', text: 'Project: FarmaFinder' },
{ type: 'spacer', lines: 1 },
{ type: 'paragraph', text: 'This document summarizes the international prior-art position for the technical concept described in the FarmaFinder patent materials.' },
{ type: 'heading', text: 'Technical scope' },
{ type: 'paragraph', text: 'The invention concerns a computer-implemented system and method for identifying a therapeutic need from the scan of an individual health card or equivalent patient-related identifier, associating that result with an authenticated user, comparing the inferred need with geolocated pharmacy inventory, and generating supply-related actions when the required product is not available.' },
{ type: 'heading', text: 'Main categories of prior art identified' },
{ type: 'number', text: 'Medicine search platforms that allow users to locate medicines by name or active ingredient.' },
{ type: 'number', text: 'Pharmacy locator systems that display nearby pharmacies and, in some cases, opening hours, distance, or approximate availability.' },
{ type: 'number', text: 'Inventory management systems used by pharmacies, distributors, or health-related retail networks.' },
{ type: 'number', text: 'Digital health applications that store user profiles, location data, reminders, or treatment-related information.' },
{ type: 'number', text: 'Reservation, referral, or notification workflows that allow a user or a pharmacy to react when a product is out of stock.' },
{ type: 'heading', text: 'Distinguishing technical features' },
{ type: 'bullet', text: 'secure capture of a health-card identifier or equivalent patient-related credential;' },
{ type: 'bullet', text: 'verification of the captured data and association with an authenticated user profile;' },
{ type: 'bullet', text: 'automatic derivation of a medicine reference or therapeutic need;' },
{ type: 'bullet', text: 'real-time comparison against pharmacy stock data from geolocated pharmacies;' },
{ type: 'bullet', text: 'ranking of pharmacies according to availability, distance, and opening status;' },
{ type: 'bullet', text: 'automatic generation of reserve, notification, order, or referral actions when stock is insufficient;' },
{ type: 'bullet', text: 'technical traceability of the event across the processing chain.' },
{ type: 'heading', text: 'Assessment' },
{ type: 'paragraph', text: 'The reviewed prior-art categories appear to disclose individual parts of the technical problem, but not the complete integrated architecture described above in a single system. In particular, the combination of patient-context capture through a health identifier, automated therapeutic inference, geolocated stock comparison, and machine-generated supply actions does not appear to be disclosed as a unified technical chain in the documents reviewed at the project level.' },
{ type: 'heading', text: 'Suggested search focus for the European search phase' },
{ type: 'bullet', text: 'patient identifier scanning;' },
{ type: 'bullet', text: 'health-card reading or optical capture of patient credentials;' },
{ type: 'bullet', text: 'medicine search and pharmacy availability systems;' },
{ type: 'bullet', text: 'pharmacy reservation and referral workflows;' },
{ type: 'bullet', text: 'location-based ranking of pharmacies;' },
{ type: 'bullet', text: 'automated inventory-driven notification or order generation;' },
{ type: 'bullet', text: 'health-related digital assistants that combine user context with stock availability.' },
{ type: 'heading', text: 'Working conclusion' },
{ type: 'paragraph', text: 'On the basis of the current project documentation, the invention is presented as a computer-implemented technical solution that integrates identification, verification, geolocation, inventory contrast, and automated supply actions in one workflow. No single reference has been identified at the project level that clearly discloses the full combination of these features.' },
{ type: 'heading', text: 'Date' },
{ type: 'paragraph', text: '13 August 2026' },
];
const PAGE_W = 595.28;
const PAGE_H = 841.89;
const MARGIN_L = 56;
const MARGIN_R = 56;
const MARGIN_T = 54;
const MARGIN_B = 50;
const CONTENT_W = PAGE_W - MARGIN_L - MARGIN_R;
function esc(s) {
return String(s).replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
}
function latin1(s) {
return Buffer.from(s, 'latin1').toString('latin1');
}
function wrapText(text, size) {
const avg = size * 0.48;
const max = Math.max(25, Math.floor(CONTENT_W / avg));
const words = String(text).split(/\s+/);
const lines = [];
let line = '';
for (const word of words) {
const candidate = line ? `${line} ${word}` : word;
if (candidate.length > max && line) {
lines.push(line);
line = word;
} else {
line = candidate;
}
}
if (line) lines.push(line);
return lines;
}
function buildPdf() {
const objects = [''];
const add = (body) => {
objects.push(body);
return objects.length - 1;
};
const fontReg = add('<< /Type /Font /Subtype /Type1 /BaseFont /Times-Roman /Encoding /WinAnsiEncoding >>');
const fontBold = add('<< /Type /Font /Subtype /Type1 /BaseFont /Times-Bold /Encoding /WinAnsiEncoding >>');
const fontIt = add('<< /Type /Font /Subtype /Type1 /BaseFont /Times-Italic /Encoding /WinAnsiEncoding >>');
const pagesTree = add('');
const contentNums = [];
const pageNums = [];
const pageContent = (pageLines, pageNo) => {
const ops = [];
let y = PAGE_H - MARGIN_T;
let numberCounter = 1;
const write = (txt, x, size, font = 'F1') => {
ops.push(`BT /${font} ${size} Tf ${x} ${y} Td (${esc(latin1(txt))}) Tj ET`);
y -= size * 1.25;
};
const ensure = (needed) => y - needed > MARGIN_B;
for (const item of pageLines) {
if (item.type === 'title') {
const lines = wrapText(item.text, 18);
for (const line of lines) write(line, MARGIN_L + 82, 18, 'F2');
y -= 4;
continue;
}
if (item.type === 'subtitle') {
const lines = wrapText(item.text, 12);
for (const line of lines) write(line, MARGIN_L + 100, 12, 'F3');
y -= 8;
continue;
}
if (item.type === 'spacer') {
y -= (item.lines || 1) * 12;
continue;
}
if (item.type === 'heading') {
if (!ensure(24)) break;
write(item.text, MARGIN_L, 13, 'F2');
y -= 4;
ops.push(`0.3 w ${MARGIN_L} ${y} m ${PAGE_W - MARGIN_R} ${y} l S`);
y -= 8;
continue;
}
if (item.type === 'paragraph') {
const lines = wrapText(item.text, 11.5);
if (!ensure(lines.length * 14 + 6)) break;
for (const line of lines) write(line, MARGIN_L, 11.5, 'F1');
y -= 2;
continue;
}
if (item.type === 'bullet') {
const lines = wrapText(item.text, 11.2);
if (!ensure(lines.length * 14 + 6)) break;
let first = true;
for (const line of lines) {
write((first ? '- ' : ' ') + line, MARGIN_L + 8, 11.2, 'F1');
first = false;
}
continue;
}
if (item.type === 'number') {
const lines = wrapText(item.text, 11.2);
if (!ensure(lines.length * 14 + 6)) break;
let first = true;
for (const line of lines) {
write((first ? `${numberCounter}. ` : ' ') + line, MARGIN_L + 8, 11.2, 'F1');
first = false;
}
numberCounter += 1;
continue;
}
}
ops.push(`BT /F1 9 Tf ${PAGE_W - 100} ${24} Td (Page ${pageNo}) Tj ET`);
return ops.join('\n');
};
const page1 = sections.slice(0, 12);
const page2 = sections.slice(12);
const pages = [page1, page2];
for (let i = 0; i < pages.length; i += 1) {
const content = pageContent(pages[i], i + 1);
contentNums.push(add(`<< /Length ${Buffer.byteLength(content, 'latin1')} >>\nstream\n${content}\nendstream`));
}
for (let i = 0; i < pages.length; i += 1) {
pageNums.push(add(`<< /Type /Page /Parent ${pagesTree} 0 R /MediaBox [0 0 ${PAGE_W} ${PAGE_H}] /Resources << /Font << /F1 ${fontReg} 0 R /F2 ${fontBold} 0 R /F3 ${fontIt} 0 R >> >> /Contents ${contentNums[i]} 0 R >>`));
}
objects[pagesTree] = `<< /Type /Pages /Kids [${pageNums.map(n => `${n} 0 R`).join(' ')}] /Count ${pageNums.length} >>`;
const catalog = add(`<< /Type /Catalog /Pages ${pagesTree} 0 R >>`);
let pdf = '%PDF-1.4\n';
const offsets = [0];
for (let i = 1; i < objects.length; i += 1) {
offsets[i] = Buffer.byteLength(pdf, 'latin1');
pdf += `${i} 0 obj\n${objects[i]}\nendobj\n`;
}
const xref = Buffer.byteLength(pdf, 'latin1');
pdf += `xref\n0 ${objects.length}\n`;
pdf += '0000000000 65535 f \n';
for (let i = 1; i < objects.length; i += 1) {
pdf += `${String(offsets[i]).padStart(10, '0')} 00000 n \n`;
}
pdf += `trailer << /Size ${objects.length} /Root ${catalog} 0 R >>\nstartxref\n${xref}\n%%EOF\n`;
fs.writeFileSync(outPath, Buffer.from(pdf, 'latin1'));
}
buildPdf();
console.log(`Wrote ${outPath}`);