From 41c4cf547be61210e68a45a98193d119ecce9422 Mon Sep 17 00:00:00 2001 From: draihan Date: Tue, 10 Oct 2023 20:09:18 -0700 Subject: [PATCH 1/2] Parse PDF into text but left out the last page --- client/next.config.js | 2 +- client/package-lock.json | 48 ++++++++++++++++- client/package.json | 5 +- client/public/sample3.pdf | Bin 0 -> 35630 bytes client/src/app/api/upload/route.ts | 60 +++++++++++++++++++++ client/src/app/page.tsx | 4 +- client/src/components/DropFile.tsx | 40 +++++--------- client/src/components/FileViewer.tsx | 75 +++++++++++++-------------- 8 files changed, 162 insertions(+), 72 deletions(-) create mode 100644 client/public/sample3.pdf create mode 100644 client/src/app/api/upload/route.ts diff --git a/client/next.config.js b/client/next.config.js index 1ad3638..47c9e05 100644 --- a/client/next.config.js +++ b/client/next.config.js @@ -20,7 +20,7 @@ const nextConfig = { "sharp$": false, "onnxruntime-node$": false, } - + config.resolve.alias.canvas = false config.resolve.alias.encoding = false return config; diff --git a/client/package-lock.json b/client/package-lock.json index 38cc627..dbaebb2 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -12,12 +12,15 @@ "@xenova/transformers": "^2.6.2", "filepond": "^4.30.4", "framer-motion": "^10.16.4", + "fs": "^0.0.1-security", "next": "latest", + "pdf2json": "^3.0.4", "react": "latest", "react-dom": "latest", "react-drag-drop-files": "^2.3.10", "react-filepond": "^7.1.2", - "react-pdf": "^7.5.0" + "react-pdf": "^7.5.0", + "uuid": "^9.0.1" }, "devDependencies": { "@types/long": "^5.0.0", @@ -5153,6 +5156,11 @@ } } }, + "node_modules/fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==" + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -7034,6 +7042,32 @@ "node": ">=8" } }, + "node_modules/pdf2json": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pdf2json/-/pdf2json-3.0.4.tgz", + "integrity": "sha512-NKmSg78W5V/T3Qvp+TPkYeARdP/XzxBTlhRGdDMrOI1beyI72JxW5u4yy5825ge3opzu4HF0xDgg+HZbYvbr4g==", + "bundleDependencies": [ + "@xmldom/xmldom" + ], + "dependencies": { + "@xmldom/xmldom": "^0.8.6" + }, + "bin": { + "pdf2json": "bin/pdf2json.js" + }, + "engines": { + "node": ">=18.12.1", + "npm": ">=8.19.2" + } + }, + "node_modules/pdf2json/node_modules/@xmldom/xmldom": { + "version": "0.8.7", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/pdfjs-dist": { "version": "3.11.174", "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", @@ -8864,6 +8898,18 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", diff --git a/client/package.json b/client/package.json index 3bac484..bda1154 100644 --- a/client/package.json +++ b/client/package.json @@ -13,12 +13,15 @@ "@xenova/transformers": "^2.6.2", "filepond": "^4.30.4", "framer-motion": "^10.16.4", + "fs": "^0.0.1-security", "next": "latest", + "pdf2json": "^3.0.4", "react": "latest", "react-dom": "latest", "react-drag-drop-files": "^2.3.10", "react-filepond": "^7.1.2", - "react-pdf": "^7.5.0" + "react-pdf": "^7.5.0", + "uuid": "^9.0.1" }, "devDependencies": { "@types/long": "^5.0.0", diff --git a/client/public/sample3.pdf b/client/public/sample3.pdf new file mode 100644 index 0000000000000000000000000000000000000000..eec5967f049bbea88134d70a9c7bdcd5f95f0424 GIT binary patch literal 35630 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 W0g%WIJOYO7uTHbEvN8SP^#1@&!G>1= literal 0 HcmV?d00001 diff --git a/client/src/app/api/upload/route.ts b/client/src/app/api/upload/route.ts new file mode 100644 index 0000000..11f92c8 --- /dev/null +++ b/client/src/app/api/upload/route.ts @@ -0,0 +1,60 @@ +import { NextRequest, NextResponse } from 'next/server'; // To handle the request and response +import { promises as fs } from 'fs'; // To save the file temporarily +import { v4 as uuidv4 } from 'uuid'; // To generate a unique filename +import PDFParser from 'pdf2json'; // To parse the pdf + +export async function POST(req: NextRequest) { + const formData: FormData = await req.formData(); + const uploadedFiles = formData.getAll('filepond'); + let fileName = ''; + let parsedText = ''; + + if (uploadedFiles && uploadedFiles.length > 0) { + const uploadedFile = uploadedFiles[1]; + console.log('Uploaded file:', uploadedFile); + + // Check if uploadedFile is of type File + if (uploadedFile instanceof File) { + // Generate a unique filename + fileName = uuidv4(); + + // Convert the uploaded file into a temporary file + const tempFilePath = `/tmp/${fileName}.pdf`; + + // Convert ArrayBuffer to Buffer + const fileBuffer = Buffer.from(await uploadedFile.arrayBuffer()); + + // Save the buffer as a file + await fs.writeFile(tempFilePath, fileBuffer); + + // Parse the pdf using pdf2json. See pdf2json docs for more info. + + // The reason I am bypassing type checks is because + // the default type definitions for pdf2json in the npm install + // do not allow for any constructor arguments. + // You can either modify the type definitions or bypass the type checks. + // I chose to bypass the type checks. + const pdfParser = new (PDFParser as any)(null, 1); + + // See pdf2json docs for more info on how the below works. + pdfParser.on('pdfParser_dataError', (errData: any) => + console.log(errData.parserError) + ); + + pdfParser.on('pdfParser_dataReady', () => { + console.log((pdfParser as any).getRawTextContent()); + parsedText = (pdfParser as any).getRawTextContent(); + }); + + pdfParser.loadPDF(tempFilePath); + } else { + console.log('Uploaded file is not in the expected format.'); + } + } else { + console.log('No files found.'); + } + + const response = new NextResponse(parsedText); + response.headers.set('FileName', fileName); + return response; +} \ No newline at end of file diff --git a/client/src/app/page.tsx b/client/src/app/page.tsx index a83acd6..9b143e3 100644 --- a/client/src/app/page.tsx +++ b/client/src/app/page.tsx @@ -13,7 +13,7 @@ import { CardBody, } from "@nextui-org/react"; -import FileUploader from "@components/DropFile"; +import DropFile from "@components/DropFile"; import FileViewer from "@components/FileViewer"; @@ -87,7 +87,7 @@ const Home = () => {

- + diff --git a/client/src/components/DropFile.tsx b/client/src/components/DropFile.tsx index 59f5ca9..9af21be 100644 --- a/client/src/components/DropFile.tsx +++ b/client/src/components/DropFile.tsx @@ -1,31 +1,17 @@ -import React, { useState } from "react"; -import { FileUploader } from "react-drag-drop-files"; +"use client"; -const fileTypes = ["PDF"]; +import { FilePond } from "react-filepond"; +import "filepond/dist/filepond.min.css"; +import { useState } from "react"; -const DropFile = () => { - const [file, setFile] = useState(); - const [isUploaded, setIsUploaded] = useState(); - - const handleChange = (file: File) => { - setFile(file); - }; - const handleFileUploaded = (file: File) => { - setIsUploaded(true); - }; +export default function DropFile() { return ( -
- -
+ ); -}; - -export default DropFile; +} diff --git a/client/src/components/FileViewer.tsx b/client/src/components/FileViewer.tsx index e8a194c..667563f 100644 --- a/client/src/components/FileViewer.tsx +++ b/client/src/components/FileViewer.tsx @@ -1,11 +1,11 @@ "use client"; -import React, { useCallback, useState } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { Button } from "@nextui-org/react"; import { pdfjs, Document, Page } from "react-pdf"; -// import "react-pdf/dist/Page/AnnotationLayer.css"; +import "react-pdf/dist/Page/AnnotationLayer.css"; import "react-pdf/dist/Page/TextLayer.css"; pdfjs.GlobalWorkerOptions.workerSrc = new URL( @@ -18,27 +18,16 @@ function highlightPattern(text: string, pattern: string) { } export default function FileViewer() { - const [searchText, setSearchText] = useState(""); + const [searchText, setSearchText] = useState(""); const [numPages, setNumPages] = useState(null); - const [pageNumber, setPageNumber] = useState(1); - // Display the first page + const [currentPageText, setCurrentPageText] = useState(""); + const [context, setContext] = useState(""); + + // Get number of pages function onDocumentLoadSuccess({ numPages }: any) { setNumPages(numPages); - setPageNumber(1); - } - - // Navigation - function changePage(offset: any) { - setPageNumber((prevPageNumber) => prevPageNumber + offset); - } - function previousPage() { - changePage(-1); - } - - function nextPage() { - changePage(1); } // Highlighting given text @@ -47,6 +36,25 @@ export default function FileViewer() { [searchText], ); + // Get text from single page + const getTextPage = useCallback( + (e: any) => + e.getTextContent().then((textContent: any) => { + let pageText: string = textContent.items + .map((s: any) => s.str) + .join(""); + setCurrentPageText(pageText); + console.log("Current page: " + pageText); + }), + [], + ); + + // Update context (still missing the last page) + useEffect(() => { + setContext(context + " " + currentPageText); + console.log("Context: " + context); + }, [currentPageText]); + // Uodate search text function onChange(event: any) { setSearchText(event.target.value); @@ -54,26 +62,6 @@ export default function FileViewer() { return (
-
-

- Page {pageNumber || (numPages ? 1 : "--")} of {numPages || "--"} -

- - -
-
- - + + {Array.from(new Array(numPages), (el, index) => ( + + ))}
); From 0f744994d2bb72b403220473ae4f9f3e193670c8 Mon Sep 17 00:00:00 2001 From: draihan Date: Tue, 10 Oct 2023 20:11:12 -0700 Subject: [PATCH 2/2] Parse PDF into text but left out the last page --- client/src/components/FileViewer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/FileViewer.tsx b/client/src/components/FileViewer.tsx index 667563f..1c0c2af 100644 --- a/client/src/components/FileViewer.tsx +++ b/client/src/components/FileViewer.tsx @@ -49,7 +49,7 @@ export default function FileViewer() { [], ); - // Update context (still missing the last page) + // Update context (still missing the last page) useEffect(() => { setContext(context + " " + currentPageText); console.log("Context: " + context);