resume-extraction/app/api/extract_resume/route.ts (96 lines of code) (raw):

import { EXTRACT_VALUES_PROMPT, MODEL } from '@/lib/constants' import { ResumeSchema } from '@/lib/resume' import { promises as fs } from 'fs' import OpenAI from 'openai' import { zodResponseFormat } from 'openai/helpers/zod' import PDFParser from 'pdf2json' const openai = new OpenAI() export const runtime = 'nodejs' function extractValues(resumeText: string): ReadableStream { console.log('Extract values from resume text:', resumeText) const stream = openai.beta.chat.completions.stream({ model: MODEL, messages: [ { role: 'system', content: EXTRACT_VALUES_PROMPT }, { role: 'user', content: resumeText } ], response_format: zodResponseFormat(ResumeSchema, 'event') }) const encoder = new TextEncoder() const readableStream = new ReadableStream({ start(controller) { stream .on('content.delta', ({ parsed }) => { console.log('content.delta parsed:', parsed) // Send the parsed data as JSON controller.enqueue(encoder.encode(JSON.stringify(parsed) + '\n')) }) .on('content.done', () => { console.log('content.done') controller.close() }) .on('error', error => { console.error('Error in OpenAI stream:', error) controller.error(error) }) } }) return readableStream } async function parsePDF(uploadedFiles: FormDataEntryValue[]): Promise<string> { return new Promise((resolve, reject) => { if (uploadedFiles && uploadedFiles.length > 0) { const uploadedFile = uploadedFiles[0] if (uploadedFile instanceof File) { const tempFilePath = `/tmp/resume.pdf` uploadedFile.arrayBuffer().then(arrayBuffer => { const fileBuffer = Buffer.from(arrayBuffer) fs.writeFile(tempFilePath, fileBuffer) .then(() => { // Parse the pdf using pdf2json const pdfParser = new (PDFParser as any)(null, 1) pdfParser.on('pdfParser_dataError', (errData: any) => { console.log(errData.parserError) reject(errData.parserError) }) pdfParser.on('pdfParser_dataReady', () => { const rawTextContent = (pdfParser as any).getRawTextContent() resolve(rawTextContent) }) pdfParser.loadPDF(tempFilePath) }) .catch(error => { console.error('Error writing file:', error) reject(error) }) }) } else { reject(new Error('Uploaded file is not of type File')) } } else { reject(new Error('No files uploaded')) } }) } export async function POST(req: Request) { try { const formData = await req.formData() const uploadedFiles = formData.getAll('files') console.log('Received files:', uploadedFiles) const resumeText = await parsePDF(uploadedFiles) console.log('Parsed resume text:', resumeText) const readableStream = extractValues(resumeText) return new Response(readableStream, { headers: { 'Content-Type': 'text/plain; charset=utf-8', 'Cache-Control': 'no-cache', Connection: 'keep-alive', 'Transfer-Encoding': 'chunked' } }) } catch (error) { console.error('Error in POST handler:', error) return new Response( JSON.stringify({ error: 'Failed to process the PDF file' }), { status: 500 } ) } }