mirror of
https://github.com/velocitatem/cvfs.git
synced 2026-05-31 08:43:37 +00:00
feat: add CV view analytics and PDF rendering for public share links
Agent-Logs-Url: https://github.com/velocitatem/cvfs/sessions/fb35fb9a-a89e-4df0-9584-109f7151509c Co-authored-by: velocitatem <60182044+velocitatem@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
b63417b8b3
commit
7435a0f1bf
@@ -9,6 +9,7 @@ from .parser import parse_docx_bytes, summarize_keywords
|
||||
from .patcher import apply_patchset
|
||||
from .ats_guard import validate_patchset
|
||||
from .docx_export import generate_patched_docx
|
||||
from .pdf_export import docx_bytes_to_pdf
|
||||
|
||||
__all__ = [
|
||||
"StructuredBlock",
|
||||
@@ -21,4 +22,5 @@ __all__ = [
|
||||
"apply_patchset",
|
||||
"validate_patchset",
|
||||
"generate_patched_docx",
|
||||
"docx_bytes_to_pdf",
|
||||
]
|
||||
|
||||
79
dlib/cv/pdf_export.py
Normal file
79
dlib/cv/pdf_export.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from io import BytesIO
|
||||
|
||||
from docx import Document
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.enums import TA_CENTER, TA_LEFT
|
||||
from reportlab.lib.pagesizes import A4
|
||||
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
|
||||
from reportlab.lib.units import cm
|
||||
from reportlab.platypus import HRFlowable, Paragraph, SimpleDocTemplate, Spacer
|
||||
|
||||
from .parser import _detect_block_type
|
||||
|
||||
_STYLES = getSampleStyleSheet()
|
||||
|
||||
_STYLE_MAP: dict[str, ParagraphStyle] = {
|
||||
"heading": ParagraphStyle(
|
||||
"CVHeading", parent=_STYLES["Normal"],
|
||||
fontSize=15, leading=20, spaceBefore=10, spaceAfter=4,
|
||||
textColor=colors.HexColor("#111111"), fontName="Helvetica-Bold",
|
||||
),
|
||||
"meta": ParagraphStyle(
|
||||
"CVMeta", parent=_STYLES["Normal"],
|
||||
fontSize=9, leading=13, spaceAfter=2, textColor=colors.HexColor("#555555"),
|
||||
),
|
||||
"summary": ParagraphStyle(
|
||||
"CVSummary", parent=_STYLES["Normal"],
|
||||
fontSize=10, leading=14, spaceAfter=6, textColor=colors.HexColor("#333333"),
|
||||
),
|
||||
"bullet": ParagraphStyle(
|
||||
"CVBullet", parent=_STYLES["Normal"],
|
||||
fontSize=10, leading=14, spaceAfter=3, leftIndent=14,
|
||||
bulletIndent=0, textColor=colors.HexColor("#222222"),
|
||||
),
|
||||
"skills": ParagraphStyle(
|
||||
"CVSkills", parent=_STYLES["Normal"],
|
||||
fontSize=10, leading=14, spaceAfter=3, textColor=colors.HexColor("#222222"),
|
||||
),
|
||||
"text": ParagraphStyle(
|
||||
"CVText", parent=_STYLES["Normal"],
|
||||
fontSize=10, leading=14, spaceAfter=4, textColor=colors.HexColor("#222222"),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def docx_bytes_to_pdf(docx_bytes: bytes) -> bytes:
|
||||
doc = Document(BytesIO(docx_bytes))
|
||||
buf = BytesIO()
|
||||
pdf = SimpleDocTemplate(
|
||||
buf, pagesize=A4,
|
||||
leftMargin=2.2 * cm, rightMargin=2.2 * cm,
|
||||
topMargin=2 * cm, bottomMargin=2 * cm,
|
||||
)
|
||||
story: list = []
|
||||
prev_type: str | None = None
|
||||
|
||||
for para in doc.paragraphs:
|
||||
text = para.text.strip()
|
||||
if not text:
|
||||
if prev_type and prev_type != "empty":
|
||||
story.append(Spacer(1, 4))
|
||||
prev_type = "empty"
|
||||
continue
|
||||
|
||||
block_type = _detect_block_type(getattr(para.style, "name", None), para)
|
||||
style = _STYLE_MAP.get(block_type, _STYLE_MAP["text"])
|
||||
|
||||
# draw separator line before new heading sections (except first)
|
||||
if block_type == "heading" and prev_type not in (None, "heading"):
|
||||
story.append(Spacer(1, 6))
|
||||
story.append(HRFlowable(width="100%", thickness=0.5, color=colors.HexColor("#cccccc")))
|
||||
|
||||
prefix = "\u2022\u00a0" if block_type == "bullet" else ""
|
||||
story.append(Paragraph(f"{prefix}{text}", style))
|
||||
prev_type = block_type
|
||||
|
||||
pdf.build(story)
|
||||
return buf.getvalue()
|
||||
Reference in New Issue
Block a user