Fix cover page: underline only 'Disclaimer', ensure page break, add SERVER_TIMEZONE env var
Mirror and run GitLab CI / build (push) Has been cancelled
Ruff / ruff (push) Has been cancelled

This commit is contained in:
admin
2026-06-20 03:10:32 +00:00
parent 0db7dcd677
commit ecd40f42c2
2 changed files with 33 additions and 41 deletions
+3
View File
@@ -36,6 +36,9 @@ ENV CELERY_BROKER_URL=redis://localhost:6379/0
ENV CELERY_RESULT_BACKEND=redis://localhost:6379/0 ENV CELERY_RESULT_BACKEND=redis://localhost:6379/0
ENV SCRAIBE_UPLOAD_DIR=/tmp/scraibe_uploads ENV SCRAIBE_UPLOAD_DIR=/tmp/scraibe_uploads
# Server timezone for document dates (e.g., America/Toronto, Europe/Berlin)
ENV SERVER_TIMEZONE=UTC
# Email and template configuration # Email and template configuration
ENV EMAIL_CONTACT_ADDRESS=support@example.com ENV EMAIL_CONTACT_ADDRESS=support@example.com
ENV EMAIL_CSS_PATH= ENV EMAIL_CSS_PATH=
+30 -41
View File
@@ -3,27 +3,24 @@ Cover-page generator for transcript and summary DOCX files.
Layout (all centered): Layout (all centered):
- 5 blank lines - 5 blank lines
- Logo from COVER_PAGE_LOGO_URL (if set)
- 3 blank lines - 3 blank lines
- Title in uppercase: "TRANSCRIPT" or "SUMMARY" - Title in uppercase: "TRANSCRIPT" or "SUMMARY"
- Next line: date of transcription (e.g. "June 19, 2026") - Next line: date of transcription (e.g. "June 19, 2026")
- Next line: "Created by <COVER_PAGE_ORGANIZATION>" - Next line: "Created by <COVER_PAGE_ORGANIZATION>"
- 3 blank lines - 3 blank lines
- Disclaimer text - Disclaimer (underlined)
- Page break (ensures content starts on page 2)
A page break is inserted after the cover page so the main content starts on page 2.
Environment variables: Environment variables:
- COVER_PAGE_ENABLED: "true"/"false" (default: false) - COVER_PAGE_ENABLED: "true"/"false" (default: false)
- COVER_PAGE_ORGANIZATION: e.g., "A.P.Strom" - COVER_PAGE_ORGANIZATION: e.g., "A.P.Strom"
- COVER_PAGE_LOGO_URL: URL of logo image to include on the cover page - SERVER_TIMEZONE: Timezone for document dates (e.g., "America/Toronto"). Defaults to "UTC".
""" """
import os import os
import io
import httpx
from datetime import datetime from datetime import datetime
from typing import Optional from typing import Optional
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
from docx import Document from docx import Document
from docx.shared import Pt from docx.shared import Pt
from docx.enum.text import WD_ALIGN_PARAGRAPH from docx.enum.text import WD_ALIGN_PARAGRAPH
@@ -31,7 +28,15 @@ from docx.oxml import OxmlElement
from docx.oxml.ns import qn from docx.oxml.ns import qn
def _add_centered_paragraph(doc: Document, text: str = "", font_size: Pt = Pt(12), bold: bool = False): def _get_server_timezone():
tz_name = (os.getenv("SERVER_TIMEZONE") or "UTC").strip()
try:
return ZoneInfo(tz_name)
except (ZoneInfoNotFoundError, KeyError, ValueError):
return ZoneInfo("UTC")
def _add_centered_paragraph(doc: Document, text: str = "", font_size: Pt = Pt(12), bold: bool = False, underline: bool = False):
"""Add a centered paragraph with given text and style.""" """Add a centered paragraph with given text and style."""
p = doc.add_paragraph() p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER p.alignment = WD_ALIGN_PARAGRAPH.CENTER
@@ -40,6 +45,7 @@ def _add_centered_paragraph(doc: Document, text: str = "", font_size: Pt = Pt(12
run.font.name = "Courier" run.font.name = "Courier"
run.font.size = font_size run.font.size = font_size
run.bold = bold run.bold = bold
run.underline = underline
return p return p
@@ -50,9 +56,10 @@ def _add_blank_lines(doc: Document, count: int):
def _add_page_break(doc: Document): def _add_page_break(doc: Document):
"""Insert a page break paragraph.""" """Insert a page break paragraph to force next content to page 2."""
p = doc.add_paragraph() p = doc.add_paragraph()
pPr = p._p.get_or_add_pPr() pPr = p._p.get_or_add_pPr()
# Clean existing formatting
for child in list(pPr): for child in list(pPr):
tag = child.tag.split("}")[-1] if "}" in child.tag else child.tag tag = child.tag.split("}")[-1] if "}" in child.tag else child.tag
if tag in ("tabs", "spacing", "ind"): if tag in ("tabs", "spacing", "ind"):
@@ -62,17 +69,6 @@ def _add_page_break(doc: Document):
pPr.append(page_break) pPr.append(page_break)
def _download_image_bytes(url: str) -> Optional[bytes]:
"""Download image from URL and return bytes, or None on failure."""
try:
with httpx.stream("GET", url, timeout=10) as resp:
if resp.status_code == 200:
return resp.content
except Exception:
pass
return None
def add_cover_page( def add_cover_page(
doc: Document, doc: Document,
title: str, title: str,
@@ -83,35 +79,23 @@ def add_cover_page(
- title: e.g., "TRANSCRIPT" or "SUMMARY" - title: e.g., "TRANSCRIPT" or "SUMMARY"
- date_str: optional date string (e.g., "June 19, 2026"); - date_str: optional date string (e.g., "June 19, 2026");
if not provided, uses today's date. if not provided, uses current server time in SERVER_TIMEZONE.
""" """
# 5 blank lines # 5 blank lines
_add_blank_lines(doc, 5) _add_blank_lines(doc, 5)
# Logo (if COVER_PAGE_LOGO_URL is set)
logo_url = (os.getenv("COVER_PAGE_LOGO_URL") or "").strip()
if logo_url:
img_bytes = _download_image_bytes(logo_url)
if img_bytes:
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
try:
# Add image centered
p.add_run().add_picture(io.BytesIO(img_bytes), width=None)
except Exception:
# Fallback: do nothing if image fails
pass
# 3 blank lines # 3 blank lines
_add_blank_lines(doc, 3) _add_blank_lines(doc, 3)
# Title in uppercase # Title in uppercase
_add_centered_paragraph(doc, text=title.upper().strip(), font_size=Pt(18), bold=True) _add_centered_paragraph(doc, text=title.upper().strip(), font_size=Pt(18), bold=True)
# Date of transcription # Date of transcription (use provided or current server time)
if not date_str: if not date_str:
date_str = datetime.utcnow().strftime("%B %d, %Y") tz = _get_server_timezone()
now = datetime.now(tz)
date_str = now.strftime("%B %d, %Y")
_add_centered_paragraph(doc, text=date_str, font_size=Pt(14)) _add_centered_paragraph(doc, text=date_str, font_size=Pt(14))
# Created by + organization # Created by + organization
@@ -122,12 +106,17 @@ def add_cover_page(
# 3 blank lines # 3 blank lines
_add_blank_lines(doc, 3) _add_blank_lines(doc, 3)
# Disclaimer # Disclaimer: only the word "Disclaimer" is underlined
disclaimer = ( disclaimer_title = "Disclaimer"
"Disclaimer\n" disclaimer_body = (
"This transcription and any summary derived therefrom may contain errors or inaccuracies." "This transcription and any summary derived therefrom may contain errors or inaccuracies."
) )
_add_centered_paragraph(doc, text=disclaimer, font_size=Pt(10))
# Underlined "Disclaimer" line
p = _add_centered_paragraph(doc, text=disclaimer_title, font_size=Pt(10), underline=True)
# Body text (not underlined)
_add_centered_paragraph(doc, text=disclaimer_body, font_size=Pt(10), underline=False)
# Page break after cover page so main content starts on page 2 # Page break after cover page so main content starts on page 2
_add_page_break(doc) _add_page_break(doc)