allow specifying conversion resolution, drop explicit dpi

This commit is contained in:
2026-03-27 13:51:56 -07:00
parent 5f68aa5567
commit 5923bff155
14 changed files with 398 additions and 94 deletions
@@ -22,6 +22,11 @@ from officeconvert.conversion import (
PHASE_EXTRACTING_NOTES,
PHASE_PDF_TO_IMAGES,
PHASE_PPTX_TO_PDF,
RESOLUTION_FHD,
RESOLUTION_HD,
RESOLUTION_QHD,
RESOLUTION_SD,
RESOLUTION_UHD,
)
from officeconvertapi.v1 import conversion_connect, conversion_pb2
@@ -31,6 +36,14 @@ from officeconvert_server.storage import S3Store
logger = logging.getLogger("uvicorn.error")
_RESOLUTION_PRESET_BY_PROTO = {
conversion_pb2.CONVERSION_RESOLUTION_SD: RESOLUTION_SD,
conversion_pb2.CONVERSION_RESOLUTION_HD: RESOLUTION_HD,
conversion_pb2.CONVERSION_RESOLUTION_FHD: RESOLUTION_FHD,
conversion_pb2.CONVERSION_RESOLUTION_QHD: RESOLUTION_QHD,
conversion_pb2.CONVERSION_RESOLUTION_UHD: RESOLUTION_UHD,
}
class ConversionServiceImpl(conversion_connect.ConversionService):
"""Implements the conversion API with in-memory state and S3 orchestration."""
@@ -54,6 +67,11 @@ class ConversionServiceImpl(conversion_connect.ConversionService):
raise ConnectError(Code.INVALID_ARGUMENT, "source_filename is required")
if not source_filename.lower().endswith(".pptx"):
raise ConnectError(Code.INVALID_ARGUMENT, "only .pptx input is supported")
resolution = request.resolution
if resolution == conversion_pb2.CONVERSION_RESOLUTION_UNSPECIFIED:
resolution = conversion_pb2.CONVERSION_RESOLUTION_FHD
if resolution not in _RESOLUTION_PRESET_BY_PROTO:
raise ConnectError(Code.INVALID_ARGUMENT, "resolution is invalid")
conversion_id = str(uuid.uuid4())
bucket_name = f"oc-{conversion_id}"
@@ -70,6 +88,7 @@ class ConversionServiceImpl(conversion_connect.ConversionService):
session = ConversionSession(
conversion_id=conversion_id,
source_filename=source_filename,
resolution=resolution,
bucket_name=bucket_name,
upload_object_key=upload_key,
status=conversion_pb2.CONVERSION_STATUS_PENDING,
@@ -186,11 +205,11 @@ class ConversionServiceImpl(conversion_connect.ConversionService):
"""Execute conversion flow and persist terminal state in memory."""
started_at = time.monotonic()
logger.info(
"Starting conversion conversion_id=%s source_filename=%s dpi=%d "
"Starting conversion conversion_id=%s source_filename=%s resolution=%s "
"timeout_caps_s[pptx_to_pdf_total=%d,pdf_to_images_total=%d]",
session.conversion_id,
session.source_filename,
self._config.conversion_image_dpi,
conversion_pb2.ConversionResolution.Name(session.resolution),
self._config.conversion_pptx_to_pdf_timeout_seconds,
self._config.conversion_pdf_to_images_timeout_seconds,
)
@@ -210,7 +229,7 @@ class ConversionServiceImpl(conversion_connect.ConversionService):
convert_pptx_to_slidedeck,
source_path,
work_dir,
dpi=self._config.conversion_image_dpi,
resolution=_RESOLUTION_PRESET_BY_PROTO[session.resolution],
pptx_to_pdf_timeout_s=self._config.conversion_pptx_to_pdf_timeout_seconds,
pdf_to_images_timeout_s=self._config.conversion_pdf_to_images_timeout_seconds,
pptx_to_pdf_base_timeout_s=self._config.conversion_pptx_to_pdf_base_timeout_seconds,
@@ -224,6 +243,20 @@ class ConversionServiceImpl(conversion_connect.ConversionService):
max_progress=max_value,
),
)
logger.info(
"Resolved conversion plan conversion_id=%s source_filename=%s "
"resolution=%s inferred_dpi=%d output_size=%dx%d "
"computed_timeouts_s[pptx_to_pdf_total=%d,pdf_to_images_total=%d,pdf_to_images_per_page=%d]",
session.conversion_id,
session.source_filename,
conversion_pb2.ConversionResolution.Name(session.resolution),
result.inferred_dpi,
result.width,
result.height,
result.pptx_to_pdf_timeout_s,
result.pdf_to_images_timeout_s,
result.pdf_to_images_page_timeout_s,
)
self._set_session_progress(
session,
phase=conversion_pb2.CONVERSION_PHASE_UPLOADING_RESULTS,
@@ -235,6 +268,8 @@ class ConversionServiceImpl(conversion_connect.ConversionService):
session,
result.slides,
result.source_filename,
result.width,
result.height,
lambda current, max_value: self._set_session_progress(
session,
phase=conversion_pb2.CONVERSION_PHASE_UPLOADING_RESULTS,
@@ -300,6 +335,8 @@ class ConversionServiceImpl(conversion_connect.ConversionService):
session: ConversionSession,
slides: list[SlideArtifact],
source_filename: str,
width: int,
height: int,
progress_callback: Callable[[int, int], None] | None = None,
) -> conversion_pb2.SlideDeck:
"""Upload generated slide images and construct API response payload."""
@@ -328,6 +365,8 @@ class ConversionServiceImpl(conversion_connect.ConversionService):
source_filename=source_filename,
slides=response_slides,
created_at=_to_timestamp(utc_now()),
width=width,
height=height,
)
async def _delayed_cleanup(self, session: ConversionSession) -> None: