"""CV text cleanup helpers for the PDF extractor. Pure module: no FastAPI imports and no HTTPException. Designer-made resumes position every glyph individually, so pypdf hands back "S K I L L S" instead of "SKILLS". In that layout a single space is glyph padding and a run of two or more spaces is the real word gap, which is what the `despace_line` decorator keys off to rebuild readable lines. """ from __future__ import annotations import re from job.candidate.decorators import despace_line, normalize_unicode @normalize_unicode @despace_line def normalize_spaced_text(text) -> str: """Turn raw pypdf output into readable text, leaving normal lines untouched. The decorators have already folded the unicode and rebuilt the glyph-padded lines; what is left is the whitespace tidy-up that every line wants. """ if not text: return "" lines = [re.sub(r" {2,}", " ", line).strip() for line in text.splitlines()] return re.sub(r"\n{3,}", "\n\n", "\n".join(lines)).strip() # Mirrors frontend Inbox.jsx sourceFrom — board name is tagged in the To address. INBOX_SOURCES = ( "Microsoft Outlook", "Career Portal", "Manual CV Upload", "LinkedIn", "Indeed", "Rozee", "Mustakbil", "Employee Referral", "Recruitment Agency", "Campus Hiring", "Walk-in", ) def _letters_only(value: str) -> str: return re.sub(r"[^a-z]", "", (value or "").lower()) def source_from_message_to(message_to: str | None) -> str: raw = (message_to or "").strip() if not raw: return "Unknown" flat = _letters_only(raw) for name in INBOX_SOURCES: if _letters_only(name) and _letters_only(name) in flat: return name return raw.split(",")[0].strip() def documents_from_message(file_name: str | None, file_path: str | None) -> list[dict]: names = [n.strip() for n in (file_name or "").split(",") if n.strip()] paths = [p.strip() for p in (file_path or "").split(",") if p.strip()] out = [] for i, name in enumerate(names): out.append({"name": name, "path": paths[i] if i < len(paths) else None}) if not out and paths: for path in paths: out.append({"name": path.rsplit("/", 1)[-1].rsplit("\\", 1)[-1], "path": path}) return out