allow specifying conversion resolution, drop explicit dpi
This commit is contained in:
@@ -16,7 +16,6 @@ class ServerConfig:
|
||||
s3_secure: bool
|
||||
s3_public_endpoint: str
|
||||
s3_session_ttl_seconds: int
|
||||
conversion_image_dpi: int
|
||||
conversion_pptx_to_pdf_timeout_seconds: int
|
||||
conversion_pdf_to_images_timeout_seconds: int
|
||||
conversion_pptx_to_pdf_base_timeout_seconds: int
|
||||
@@ -35,7 +34,6 @@ def load_server_config() -> ServerConfig:
|
||||
s3_secure=os.getenv("S3_USE_SSL", "false").lower() == "true",
|
||||
s3_public_endpoint=os.getenv("S3_PUBLIC_ENDPOINT", "localhost:8333"),
|
||||
s3_session_ttl_seconds=int(os.getenv("S3_SESSION_TTL_SECONDS", "3600")),
|
||||
conversion_image_dpi=int(os.getenv("CONVERSION_IMAGE_DPI", "72")),
|
||||
conversion_pptx_to_pdf_timeout_seconds=int(
|
||||
os.getenv("CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS", "180")
|
||||
),
|
||||
|
||||
@@ -19,6 +19,7 @@ class ConversionSession:
|
||||
|
||||
conversion_id: str
|
||||
source_filename: str
|
||||
resolution: conversion_pb2.ConversionResolution
|
||||
bucket_name: str
|
||||
upload_object_key: str
|
||||
status: conversion_pb2.ConversionStatus
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user