Skip to content

Commit a3c8752

Browse files
authored
Merge pull request #26 from HappyHackingSpace/feat/pdf-extraction-improvement
feat: switch to pdfplumber for improved resume text extraction
2 parents 382d8f1 + 5399671 commit a3c8752

3 files changed

Lines changed: 20 additions & 16 deletions

File tree

levelup/app.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import io
21
import json
32
import re
43
from typing import Any, cast
54

65
import google.generativeai as genai
76
import pandas as pd # type: ignore[import-untyped]
8-
import pypdf
7+
import pdfplumber
98
import streamlit as st
109

1110
from levelup import config
@@ -23,11 +22,10 @@
2322

2423
def extract_text_from_pdf(uploaded_file: Any) -> str | None:
2524
try:
26-
pdf_reader = pypdf.PdfReader(io.BytesIO(uploaded_file.read()))
27-
parts: list[str] = []
28-
for page in pdf_reader.pages:
29-
parts.append(page.extract_text() or "")
30-
return "\n".join(parts).strip()
25+
with pdfplumber.open(uploaded_file) as pdf:
26+
parts = [page.extract_text() or "" for page in pdf.pages]
27+
text = "\n".join(parts).strip()
28+
return text
3129
except Exception as e:
3230
st.error(f"PDF reading error: {e}")
3331
return None

pyproject.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@ dependencies = [
2323
"metatron>=0.5",
2424
"psycopg2-binary>=2.9.11",
2525
"pydantic>=2.12.3",
26-
"pypdf>=6.1.3",
2726
"sentry-sdk>=2.43.0",
2827
"slowapi>=0.1.9",
2928
"sqlalchemy>=2.0.44",
3029
"sqlalchemy-utils>=0.42.0",
3130
"starlette>=0.49.1",
3231
"streamlit>=1.51.0",
33-
"pytest-mock==3.15.1"
32+
"pytest-mock==3.15.1",
33+
"pdfplumber==0.11.8"
3434
]
3535

3636
[dependency-groups]
@@ -166,7 +166,6 @@ module = [
166166
"google.generativeai.*",
167167
"streamlit.*",
168168
"metatron.*",
169-
"pypdf.*",
170169
"chromedriver_autoinstaller.*",
171170
"selenium.*",
172171
"trafilatura.*",

tests/test_resume.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import io
21
import os
32
import sys
3+
from io import BytesIO
44
from unittest.mock import MagicMock
55

66
from pytest_mock import MockerFixture
@@ -22,15 +22,22 @@
2222

2323

2424
def test_extract_text_from_pdf(mocker: MockerFixture) -> None:
25-
"""Test extract_text_from_pdf function."""
26-
mock_reader = MagicMock()
2725
mock_page = MagicMock()
2826
mock_page.extract_text.return_value = "test"
29-
mock_reader.pages = [mock_page]
3027

31-
mocker.patch("levelup.app.pypdf.PdfReader", return_value=mock_reader)
28+
mock_pdf = MagicMock()
29+
mock_pdf.pages = [mock_page]
3230

33-
assert extract_text_from_pdf(io.BytesIO(b"test")) == "test"
31+
mock_open = mocker.patch("levelup.app.pdfplumber.open")
32+
mock_open.return_value.__enter__.return_value = mock_pdf
33+
mock_open.return_value.__exit__.return_value = False
34+
35+
fake_file = BytesIO(b"%PDF-1.4 fake content")
36+
37+
text = extract_text_from_pdf(fake_file)
38+
39+
assert text == "test"
40+
mock_open.assert_called_once_with(fake_file)
3441

3542

3643
def test_analyzecv_pdf_withllm_success(mocker: MockerFixture) -> None:

0 commit comments

Comments
 (0)