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
-1
View File
@@ -4,7 +4,6 @@ S3_USE_SSL=false
S3_ACCESS_KEY=minioadmin S3_ACCESS_KEY=minioadmin
S3_SECRET_KEY=minioadmin S3_SECRET_KEY=minioadmin
S3_SESSION_TTL_SECONDS=3600 S3_SESSION_TTL_SECONDS=3600
CONVERSION_IMAGE_DPI=72
CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS=180 CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS=180
CONVERSION_PDF_TO_IMAGES_TIMEOUT_SECONDS=1800 CONVERSION_PDF_TO_IMAGES_TIMEOUT_SECONDS=1800
CONVERSION_PPTX_TO_PDF_BASE_TIMEOUT_SECONDS=45 CONVERSION_PPTX_TO_PDF_BASE_TIMEOUT_SECONDS=45
-1
View File
@@ -35,7 +35,6 @@ run-server:
export S3_ACCESS_KEY="$${S3_ACCESS_KEY:-minioadmin}"; \ export S3_ACCESS_KEY="$${S3_ACCESS_KEY:-minioadmin}"; \
export S3_SECRET_KEY="$${S3_SECRET_KEY:-minioadmin}"; \ export S3_SECRET_KEY="$${S3_SECRET_KEY:-minioadmin}"; \
export S3_SESSION_TTL_SECONDS="$${S3_SESSION_TTL_SECONDS:-3600}"; \ export S3_SESSION_TTL_SECONDS="$${S3_SESSION_TTL_SECONDS:-3600}"; \
export CONVERSION_IMAGE_DPI="$${CONVERSION_IMAGE_DPI:-72}"; \
export CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS="$${CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS:-180}"; \ export CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS="$${CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS:-180}"; \
export CONVERSION_PDF_TO_IMAGES_TIMEOUT_SECONDS="$${CONVERSION_PDF_TO_IMAGES_TIMEOUT_SECONDS:-1800}"; \ export CONVERSION_PDF_TO_IMAGES_TIMEOUT_SECONDS="$${CONVERSION_PDF_TO_IMAGES_TIMEOUT_SECONDS:-1800}"; \
export CONVERSION_PPTX_TO_PDF_BASE_TIMEOUT_SECONDS="$${CONVERSION_PPTX_TO_PDF_BASE_TIMEOUT_SECONDS:-45}"; \ export CONVERSION_PPTX_TO_PDF_BASE_TIMEOUT_SECONDS="$${CONVERSION_PPTX_TO_PDF_BASE_TIMEOUT_SECONDS:-45}"; \
+5 -3
View File
@@ -94,7 +94,7 @@ make run-server
- defaults S3 endpoint to `localhost:8333` for host-based development - defaults S3 endpoint to `localhost:8333` for host-based development
- auto-normalizes `seaweedfs:8333` to `localhost:8333` for host runs - auto-normalizes `seaweedfs:8333` to `localhost:8333` for host runs
- supports optional `UVICORN_HOST` and `UVICORN_PORT` overrides - supports optional `UVICORN_HOST` and `UVICORN_PORT` overrides
- exposes conversion tuning vars (`CONVERSION_IMAGE_DPI`, `CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS`, `CONVERSION_PDF_TO_IMAGES_TIMEOUT_SECONDS`) - exposes conversion timeout tuning vars (`CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS`, `CONVERSION_PDF_TO_IMAGES_TIMEOUT_SECONDS`)
Server endpoint base URL: Server endpoint base URL:
@@ -107,7 +107,7 @@ Create a conversion request:
```bash ```bash
curl \ curl \
--header "Content-Type: application/json" \ --header "Content-Type: application/json" \
--data '{"sourceFilename":"example.pptx"}' \ --data '{"sourceFilename":"example.pptx","resolution":"CONVERSION_RESOLUTION_FHD"}' \
http://localhost:8080/officeconvertapi.v1.ConversionService/CreateConversion http://localhost:8080/officeconvertapi.v1.ConversionService/CreateConversion
``` ```
@@ -139,6 +139,8 @@ Use `.env.example` as your baseline env configuration.
If conversion fails on larger decks, tune these environment variables: If conversion fails on larger decks, tune these environment variables:
- `CONVERSION_IMAGE_DPI` (default `72`): lower values reduce image generation time. - `CreateConversionRequest.resolution` controls output dimensions via presets: `SD`, `HD`, `FHD`, `QHD`, `UHD`.
- Omitting `resolution` (or sending `CONVERSION_RESOLUTION_UNSPECIFIED`) defaults to `FHD`.
- Rasterization DPI is inferred automatically from source slide size and selected output dimensions.
- `CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS` (default `180`): timeout for LibreOffice export. - `CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS` (default `180`): timeout for LibreOffice export.
- `CONVERSION_PDF_TO_IMAGES_TIMEOUT_SECONDS` (default `1800`): timeout for Poppler rasterization. - `CONVERSION_PDF_TO_IMAGES_TIMEOUT_SECONDS` (default `1800`): timeout for Poppler rasterization.
+2
View File
@@ -46,9 +46,11 @@ func (c *Client) SetPollInterval(interval time.Duration) {
func (c *Client) CreateConversion( func (c *Client) CreateConversion(
ctx context.Context, ctx context.Context,
sourceFilename string, sourceFilename string,
resolution officeconvertapiv1.ConversionResolution,
) (*officeconvertapiv1.CreateConversionResponse, error) { ) (*officeconvertapiv1.CreateConversionResponse, error) {
req := connect.NewRequest(&officeconvertapiv1.CreateConversionRequest{ req := connect.NewRequest(&officeconvertapiv1.CreateConversionRequest{
SourceFilename: sourceFilename, SourceFilename: sourceFilename,
Resolution: resolution,
}) })
res, err := c.rpc.CreateConversion(ctx, req) res, err := c.rpc.CreateConversion(ctx, req)
if err != nil { if err != nil {
@@ -16,7 +16,11 @@ type ConversionResult struct {
// ConvertPPTXFile runs the full create-upload-start-wait-fetch flow. // ConvertPPTXFile runs the full create-upload-start-wait-fetch flow.
func (c *Client) ConvertPPTXFile(ctx context.Context, localPPTXPath string) (*ConversionResult, error) { func (c *Client) ConvertPPTXFile(ctx context.Context, localPPTXPath string) (*ConversionResult, error) {
createRes, err := c.CreateConversion(ctx, filepath.Base(localPPTXPath)) createRes, err := c.CreateConversion(
ctx,
filepath.Base(localPPTXPath),
officeconvertapiv1.ConversionResolution_CONVERSION_RESOLUTION_UNSPECIFIED,
)
if err != nil { if err != nil {
return nil, fmt.Errorf("create conversion: %w", err) return nil, fmt.Errorf("create conversion: %w", err)
} }
-1
View File
@@ -27,7 +27,6 @@ services:
S3_ACCESS_KEY: ${S3_ACCESS_KEY:-minioadmin} S3_ACCESS_KEY: ${S3_ACCESS_KEY:-minioadmin}
S3_SECRET_KEY: ${S3_SECRET_KEY:-minioadmin} S3_SECRET_KEY: ${S3_SECRET_KEY:-minioadmin}
S3_SESSION_TTL_SECONDS: ${S3_SESSION_TTL_SECONDS:-3600} S3_SESSION_TTL_SECONDS: ${S3_SESSION_TTL_SECONDS:-3600}
CONVERSION_IMAGE_DPI: ${CONVERSION_IMAGE_DPI:-72}
CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS: ${CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS:-180} CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS: ${CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS:-180}
CONVERSION_PDF_TO_IMAGES_TIMEOUT_SECONDS: ${CONVERSION_PDF_TO_IMAGES_TIMEOUT_SECONDS:-1800} CONVERSION_PDF_TO_IMAGES_TIMEOUT_SECONDS: ${CONVERSION_PDF_TO_IMAGES_TIMEOUT_SECONDS:-1800}
CONVERSION_PPTX_TO_PDF_BASE_TIMEOUT_SECONDS: ${CONVERSION_PPTX_TO_PDF_BASE_TIMEOUT_SECONDS:-45} CONVERSION_PPTX_TO_PDF_BASE_TIMEOUT_SECONDS: ${CONVERSION_PPTX_TO_PDF_BASE_TIMEOUT_SECONDS:-45}
+139 -42
View File
@@ -137,6 +137,65 @@ func (ConversionPhase) EnumDescriptor() ([]byte, []int) {
return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{1} return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{1}
} }
// ConversionResolution represents preset output quality targets.
type ConversionResolution int32
const (
ConversionResolution_CONVERSION_RESOLUTION_UNSPECIFIED ConversionResolution = 0
ConversionResolution_CONVERSION_RESOLUTION_SD ConversionResolution = 1
ConversionResolution_CONVERSION_RESOLUTION_HD ConversionResolution = 2
ConversionResolution_CONVERSION_RESOLUTION_FHD ConversionResolution = 3
ConversionResolution_CONVERSION_RESOLUTION_QHD ConversionResolution = 4
ConversionResolution_CONVERSION_RESOLUTION_UHD ConversionResolution = 5
)
// Enum value maps for ConversionResolution.
var (
ConversionResolution_name = map[int32]string{
0: "CONVERSION_RESOLUTION_UNSPECIFIED",
1: "CONVERSION_RESOLUTION_SD",
2: "CONVERSION_RESOLUTION_HD",
3: "CONVERSION_RESOLUTION_FHD",
4: "CONVERSION_RESOLUTION_QHD",
5: "CONVERSION_RESOLUTION_UHD",
}
ConversionResolution_value = map[string]int32{
"CONVERSION_RESOLUTION_UNSPECIFIED": 0,
"CONVERSION_RESOLUTION_SD": 1,
"CONVERSION_RESOLUTION_HD": 2,
"CONVERSION_RESOLUTION_FHD": 3,
"CONVERSION_RESOLUTION_QHD": 4,
"CONVERSION_RESOLUTION_UHD": 5,
}
)
func (x ConversionResolution) Enum() *ConversionResolution {
p := new(ConversionResolution)
*p = x
return p
}
func (x ConversionResolution) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ConversionResolution) Descriptor() protoreflect.EnumDescriptor {
return file_officeconvertapi_v1_conversion_proto_enumTypes[2].Descriptor()
}
func (ConversionResolution) Type() protoreflect.EnumType {
return &file_officeconvertapi_v1_conversion_proto_enumTypes[2]
}
func (x ConversionResolution) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ConversionResolution.Descriptor instead.
func (ConversionResolution) EnumDescriptor() ([]byte, []int) {
return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{2}
}
// Slide contains extracted notes and the rendered image URL for one slide. // Slide contains extracted notes and the rendered image URL for one slide.
type Slide struct { type Slide struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
@@ -205,6 +264,8 @@ type SlideDeck struct {
SourceFilename string `protobuf:"bytes,2,opt,name=source_filename,json=sourceFilename,proto3" json:"source_filename,omitempty"` SourceFilename string `protobuf:"bytes,2,opt,name=source_filename,json=sourceFilename,proto3" json:"source_filename,omitempty"`
Slides []*Slide `protobuf:"bytes,3,rep,name=slides,proto3" json:"slides,omitempty"` Slides []*Slide `protobuf:"bytes,3,rep,name=slides,proto3" json:"slides,omitempty"`
CreatedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` CreatedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
Width int32 `protobuf:"varint,5,opt,name=width,proto3" json:"width,omitempty"`
Height int32 `protobuf:"varint,6,opt,name=height,proto3" json:"height,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@@ -267,10 +328,25 @@ func (x *SlideDeck) GetCreatedAt() *timestamppb.Timestamp {
return nil return nil
} }
func (x *SlideDeck) GetWidth() int32 {
if x != nil {
return x.Width
}
return 0
}
func (x *SlideDeck) GetHeight() int32 {
if x != nil {
return x.Height
}
return 0
}
// CreateConversionRequest starts a conversion session. // CreateConversionRequest starts a conversion session.
type CreateConversionRequest struct { type CreateConversionRequest struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
SourceFilename string `protobuf:"bytes,1,opt,name=source_filename,json=sourceFilename,proto3" json:"source_filename,omitempty"` SourceFilename string `protobuf:"bytes,1,opt,name=source_filename,json=sourceFilename,proto3" json:"source_filename,omitempty"`
Resolution ConversionResolution `protobuf:"varint,2,opt,name=resolution,proto3,enum=officeconvertapi.v1.ConversionResolution" json:"resolution,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@@ -312,6 +388,13 @@ func (x *CreateConversionRequest) GetSourceFilename() string {
return "" return ""
} }
func (x *CreateConversionRequest) GetResolution() ConversionResolution {
if x != nil {
return x.Resolution
}
return ConversionResolution_CONVERSION_RESOLUTION_UNSPECIFIED
}
// CreateConversionResponse returns upload details for the session. // CreateConversionResponse returns upload details for the session.
type CreateConversionResponse struct { type CreateConversionResponse struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
@@ -822,15 +905,20 @@ const file_officeconvertapi_v1_conversion_proto_rawDesc = "" +
"\x05index\x18\x01 \x01(\x05R\x05index\x12\x1f\n" + "\x05index\x18\x01 \x01(\x05R\x05index\x12\x1f\n" +
"\vnotes_plain\x18\x02 \x01(\tR\n" + "\vnotes_plain\x18\x02 \x01(\tR\n" +
"notesPlain\x12\x1b\n" + "notesPlain\x12\x1b\n" +
"\timage_url\x18\x03 \x01(\tR\bimageUrl\"\xc8\x01\n" + "\timage_url\x18\x03 \x01(\tR\bimageUrl\"\xf6\x01\n" +
"\tSlideDeck\x12#\n" + "\tSlideDeck\x12#\n" +
"\rconversion_id\x18\x01 \x01(\tR\fconversionId\x12'\n" + "\rconversion_id\x18\x01 \x01(\tR\fconversionId\x12'\n" +
"\x0fsource_filename\x18\x02 \x01(\tR\x0esourceFilename\x122\n" + "\x0fsource_filename\x18\x02 \x01(\tR\x0esourceFilename\x122\n" +
"\x06slides\x18\x03 \x03(\v2\x1a.officeconvertapi.v1.SlideR\x06slides\x129\n" + "\x06slides\x18\x03 \x03(\v2\x1a.officeconvertapi.v1.SlideR\x06slides\x129\n" +
"\n" + "\n" +
"created_at\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\"B\n" + "created_at\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x12\x14\n" +
"\x05width\x18\x05 \x01(\x05R\x05width\x12\x16\n" +
"\x06height\x18\x06 \x01(\x05R\x06height\"\x8d\x01\n" +
"\x17CreateConversionRequest\x12'\n" + "\x17CreateConversionRequest\x12'\n" +
"\x0fsource_filename\x18\x01 \x01(\tR\x0esourceFilename\"\xea\x01\n" + "\x0fsource_filename\x18\x01 \x01(\tR\x0esourceFilename\x12I\n" +
"\n" +
"resolution\x18\x02 \x01(\x0e2).officeconvertapi.v1.ConversionResolutionR\n" +
"resolution\"\xea\x01\n" +
"\x18CreateConversionResponse\x12#\n" + "\x18CreateConversionResponse\x12#\n" +
"\rconversion_id\x18\x01 \x01(\tR\fconversionId\x12#\n" + "\rconversion_id\x18\x01 \x01(\tR\fconversionId\x12#\n" +
"\rupload_bucket\x18\x02 \x01(\tR\fuploadBucket\x12*\n" + "\rupload_bucket\x18\x02 \x01(\tR\fuploadBucket\x12*\n" +
@@ -877,7 +965,14 @@ const file_officeconvertapi_v1_conversion_proto_rawDesc = "" +
"!CONVERSION_PHASE_EXTRACTING_NOTES\x10\x02\x12 \n" + "!CONVERSION_PHASE_EXTRACTING_NOTES\x10\x02\x12 \n" +
"\x1cCONVERSION_PHASE_PPTX_TO_PDF\x10\x03\x12\"\n" + "\x1cCONVERSION_PHASE_PPTX_TO_PDF\x10\x03\x12\"\n" +
"\x1eCONVERSION_PHASE_PDF_TO_IMAGES\x10\x04\x12&\n" + "\x1eCONVERSION_PHASE_PDF_TO_IMAGES\x10\x04\x12&\n" +
"\"CONVERSION_PHASE_UPLOADING_RESULTS\x10\x052\xcc\x04\n" + "\"CONVERSION_PHASE_UPLOADING_RESULTS\x10\x05*\xd6\x01\n" +
"\x14ConversionResolution\x12%\n" +
"!CONVERSION_RESOLUTION_UNSPECIFIED\x10\x00\x12\x1c\n" +
"\x18CONVERSION_RESOLUTION_SD\x10\x01\x12\x1c\n" +
"\x18CONVERSION_RESOLUTION_HD\x10\x02\x12\x1d\n" +
"\x19CONVERSION_RESOLUTION_FHD\x10\x03\x12\x1d\n" +
"\x19CONVERSION_RESOLUTION_QHD\x10\x04\x12\x1d\n" +
"\x19CONVERSION_RESOLUTION_UHD\x10\x052\xcc\x04\n" +
"\x11ConversionService\x12q\n" + "\x11ConversionService\x12q\n" +
"\x10CreateConversion\x12,.officeconvertapi.v1.CreateConversionRequest\x1a-.officeconvertapi.v1.CreateConversionResponse\"\x00\x12n\n" + "\x10CreateConversion\x12,.officeconvertapi.v1.CreateConversionRequest\x1a-.officeconvertapi.v1.CreateConversionResponse\"\x00\x12n\n" +
"\x0fStartConversion\x12+.officeconvertapi.v1.StartConversionRequest\x1a,.officeconvertapi.v1.StartConversionResponse\"\x00\x12z\n" + "\x0fStartConversion\x12+.officeconvertapi.v1.StartConversionRequest\x1a,.officeconvertapi.v1.StartConversionResponse\"\x00\x12z\n" +
@@ -897,49 +992,51 @@ func file_officeconvertapi_v1_conversion_proto_rawDescGZIP() []byte {
return file_officeconvertapi_v1_conversion_proto_rawDescData return file_officeconvertapi_v1_conversion_proto_rawDescData
} }
var file_officeconvertapi_v1_conversion_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_officeconvertapi_v1_conversion_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
var file_officeconvertapi_v1_conversion_proto_msgTypes = make([]protoimpl.MessageInfo, 12) var file_officeconvertapi_v1_conversion_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
var file_officeconvertapi_v1_conversion_proto_goTypes = []any{ var file_officeconvertapi_v1_conversion_proto_goTypes = []any{
(ConversionStatus)(0), // 0: officeconvertapi.v1.ConversionStatus (ConversionStatus)(0), // 0: officeconvertapi.v1.ConversionStatus
(ConversionPhase)(0), // 1: officeconvertapi.v1.ConversionPhase (ConversionPhase)(0), // 1: officeconvertapi.v1.ConversionPhase
(*Slide)(nil), // 2: officeconvertapi.v1.Slide (ConversionResolution)(0), // 2: officeconvertapi.v1.ConversionResolution
(*SlideDeck)(nil), // 3: officeconvertapi.v1.SlideDeck (*Slide)(nil), // 3: officeconvertapi.v1.Slide
(*CreateConversionRequest)(nil), // 4: officeconvertapi.v1.CreateConversionRequest (*SlideDeck)(nil), // 4: officeconvertapi.v1.SlideDeck
(*CreateConversionResponse)(nil), // 5: officeconvertapi.v1.CreateConversionResponse (*CreateConversionRequest)(nil), // 5: officeconvertapi.v1.CreateConversionRequest
(*StartConversionRequest)(nil), // 6: officeconvertapi.v1.StartConversionRequest (*CreateConversionResponse)(nil), // 6: officeconvertapi.v1.CreateConversionResponse
(*StartConversionResponse)(nil), // 7: officeconvertapi.v1.StartConversionResponse (*StartConversionRequest)(nil), // 7: officeconvertapi.v1.StartConversionRequest
(*GetConversionStatusRequest)(nil), // 8: officeconvertapi.v1.GetConversionStatusRequest (*StartConversionResponse)(nil), // 8: officeconvertapi.v1.StartConversionResponse
(*GetConversionStatusResponse)(nil), // 9: officeconvertapi.v1.GetConversionStatusResponse (*GetConversionStatusRequest)(nil), // 9: officeconvertapi.v1.GetConversionStatusRequest
(*GetSlideDeckRequest)(nil), // 10: officeconvertapi.v1.GetSlideDeckRequest (*GetConversionStatusResponse)(nil), // 10: officeconvertapi.v1.GetConversionStatusResponse
(*GetSlideDeckResponse)(nil), // 11: officeconvertapi.v1.GetSlideDeckResponse (*GetSlideDeckRequest)(nil), // 11: officeconvertapi.v1.GetSlideDeckRequest
(*DeleteConversionRequest)(nil), // 12: officeconvertapi.v1.DeleteConversionRequest (*GetSlideDeckResponse)(nil), // 12: officeconvertapi.v1.GetSlideDeckResponse
(*DeleteConversionResponse)(nil), // 13: officeconvertapi.v1.DeleteConversionResponse (*DeleteConversionRequest)(nil), // 13: officeconvertapi.v1.DeleteConversionRequest
(*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp (*DeleteConversionResponse)(nil), // 14: officeconvertapi.v1.DeleteConversionResponse
(*timestamppb.Timestamp)(nil), // 15: google.protobuf.Timestamp
} }
var file_officeconvertapi_v1_conversion_proto_depIdxs = []int32{ var file_officeconvertapi_v1_conversion_proto_depIdxs = []int32{
2, // 0: officeconvertapi.v1.SlideDeck.slides:type_name -> officeconvertapi.v1.Slide 3, // 0: officeconvertapi.v1.SlideDeck.slides:type_name -> officeconvertapi.v1.Slide
14, // 1: officeconvertapi.v1.SlideDeck.created_at:type_name -> google.protobuf.Timestamp 15, // 1: officeconvertapi.v1.SlideDeck.created_at:type_name -> google.protobuf.Timestamp
14, // 2: officeconvertapi.v1.CreateConversionResponse.expires_at:type_name -> google.protobuf.Timestamp 2, // 2: officeconvertapi.v1.CreateConversionRequest.resolution:type_name -> officeconvertapi.v1.ConversionResolution
0, // 3: officeconvertapi.v1.StartConversionResponse.status:type_name -> officeconvertapi.v1.ConversionStatus 15, // 3: officeconvertapi.v1.CreateConversionResponse.expires_at:type_name -> google.protobuf.Timestamp
0, // 4: officeconvertapi.v1.GetConversionStatusResponse.status:type_name -> officeconvertapi.v1.ConversionStatus 0, // 4: officeconvertapi.v1.StartConversionResponse.status:type_name -> officeconvertapi.v1.ConversionStatus
14, // 5: officeconvertapi.v1.GetConversionStatusResponse.updated_at:type_name -> google.protobuf.Timestamp 0, // 5: officeconvertapi.v1.GetConversionStatusResponse.status:type_name -> officeconvertapi.v1.ConversionStatus
1, // 6: officeconvertapi.v1.GetConversionStatusResponse.phase:type_name -> officeconvertapi.v1.ConversionPhase 15, // 6: officeconvertapi.v1.GetConversionStatusResponse.updated_at:type_name -> google.protobuf.Timestamp
3, // 7: officeconvertapi.v1.GetSlideDeckResponse.slide_deck:type_name -> officeconvertapi.v1.SlideDeck 1, // 7: officeconvertapi.v1.GetConversionStatusResponse.phase:type_name -> officeconvertapi.v1.ConversionPhase
4, // 8: officeconvertapi.v1.ConversionService.CreateConversion:input_type -> officeconvertapi.v1.CreateConversionRequest 4, // 8: officeconvertapi.v1.GetSlideDeckResponse.slide_deck:type_name -> officeconvertapi.v1.SlideDeck
6, // 9: officeconvertapi.v1.ConversionService.StartConversion:input_type -> officeconvertapi.v1.StartConversionRequest 5, // 9: officeconvertapi.v1.ConversionService.CreateConversion:input_type -> officeconvertapi.v1.CreateConversionRequest
8, // 10: officeconvertapi.v1.ConversionService.GetConversionStatus:input_type -> officeconvertapi.v1.GetConversionStatusRequest 7, // 10: officeconvertapi.v1.ConversionService.StartConversion:input_type -> officeconvertapi.v1.StartConversionRequest
10, // 11: officeconvertapi.v1.ConversionService.GetSlideDeck:input_type -> officeconvertapi.v1.GetSlideDeckRequest 9, // 11: officeconvertapi.v1.ConversionService.GetConversionStatus:input_type -> officeconvertapi.v1.GetConversionStatusRequest
12, // 12: officeconvertapi.v1.ConversionService.DeleteConversion:input_type -> officeconvertapi.v1.DeleteConversionRequest 11, // 12: officeconvertapi.v1.ConversionService.GetSlideDeck:input_type -> officeconvertapi.v1.GetSlideDeckRequest
5, // 13: officeconvertapi.v1.ConversionService.CreateConversion:output_type -> officeconvertapi.v1.CreateConversionResponse 13, // 13: officeconvertapi.v1.ConversionService.DeleteConversion:input_type -> officeconvertapi.v1.DeleteConversionRequest
7, // 14: officeconvertapi.v1.ConversionService.StartConversion:output_type -> officeconvertapi.v1.StartConversionResponse 6, // 14: officeconvertapi.v1.ConversionService.CreateConversion:output_type -> officeconvertapi.v1.CreateConversionResponse
9, // 15: officeconvertapi.v1.ConversionService.GetConversionStatus:output_type -> officeconvertapi.v1.GetConversionStatusResponse 8, // 15: officeconvertapi.v1.ConversionService.StartConversion:output_type -> officeconvertapi.v1.StartConversionResponse
11, // 16: officeconvertapi.v1.ConversionService.GetSlideDeck:output_type -> officeconvertapi.v1.GetSlideDeckResponse 10, // 16: officeconvertapi.v1.ConversionService.GetConversionStatus:output_type -> officeconvertapi.v1.GetConversionStatusResponse
13, // 17: officeconvertapi.v1.ConversionService.DeleteConversion:output_type -> officeconvertapi.v1.DeleteConversionResponse 12, // 17: officeconvertapi.v1.ConversionService.GetSlideDeck:output_type -> officeconvertapi.v1.GetSlideDeckResponse
13, // [13:18] is the sub-list for method output_type 14, // 18: officeconvertapi.v1.ConversionService.DeleteConversion:output_type -> officeconvertapi.v1.DeleteConversionResponse
8, // [8:13] is the sub-list for method input_type 14, // [14:19] is the sub-list for method output_type
8, // [8:8] is the sub-list for extension type_name 9, // [9:14] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension extendee 9, // [9:9] is the sub-list for extension type_name
0, // [0:8] is the sub-list for field type_name 9, // [9:9] is the sub-list for extension extendee
0, // [0:9] is the sub-list for field type_name
} }
func init() { file_officeconvertapi_v1_conversion_proto_init() } func init() { file_officeconvertapi_v1_conversion_proto_init() }
@@ -952,7 +1049,7 @@ func file_officeconvertapi_v1_conversion_proto_init() {
File: protoimpl.DescBuilder{ File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_officeconvertapi_v1_conversion_proto_rawDesc), len(file_officeconvertapi_v1_conversion_proto_rawDesc)), RawDescriptor: unsafe.Slice(unsafe.StringData(file_officeconvertapi_v1_conversion_proto_rawDesc), len(file_officeconvertapi_v1_conversion_proto_rawDesc)),
NumEnums: 2, NumEnums: 3,
NumMessages: 12, NumMessages: 12,
NumExtensions: 0, NumExtensions: 0,
NumServices: 1, NumServices: 1,
@@ -25,7 +25,7 @@ _sym_db = _symbol_database.Default()
from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$officeconvertapi/v1/conversion.proto\x12\x13officeconvertapi.v1\x1a\x1fgoogle/protobuf/timestamp.proto\"[\n\x05Slide\x12\x14\n\x05index\x18\x01 \x01(\x05R\x05index\x12\x1f\n\x0bnotes_plain\x18\x02 \x01(\tR\nnotesPlain\x12\x1b\n\timage_url\x18\x03 \x01(\tR\x08imageUrl\"\xc8\x01\n\tSlideDeck\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\x12\'\n\x0fsource_filename\x18\x02 \x01(\tR\x0esourceFilename\x12\x32\n\x06slides\x18\x03 \x03(\x0b\x32\x1a.officeconvertapi.v1.SlideR\x06slides\x12\x39\n\ncreated_at\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\tcreatedAt\"B\n\x17\x43reateConversionRequest\x12\'\n\x0fsource_filename\x18\x01 \x01(\tR\x0esourceFilename\"\xea\x01\n\x18\x43reateConversionResponse\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\x12#\n\rupload_bucket\x18\x02 \x01(\tR\x0cuploadBucket\x12*\n\x11upload_object_key\x18\x03 \x01(\tR\x0fuploadObjectKey\x12\x1d\n\nupload_url\x18\x04 \x01(\tR\tuploadUrl\x12\x39\n\nexpires_at\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\texpiresAt\"=\n\x16StartConversionRequest\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\"}\n\x17StartConversionResponse\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\x12=\n\x06status\x18\x02 \x01(\x0e\x32%.officeconvertapi.v1.ConversionStatusR\x06status\"A\n\x1aGetConversionStatusRequest\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\"\xeb\x02\n\x1bGetConversionStatusResponse\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\x12=\n\x06status\x18\x02 \x01(\x0e\x32%.officeconvertapi.v1.ConversionStatusR\x06status\x12#\n\rerror_message\x18\x03 \x01(\tR\x0c\x65rrorMessage\x12\x39\n\nupdated_at\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\tupdatedAt\x12:\n\x05phase\x18\x05 \x01(\x0e\x32$.officeconvertapi.v1.ConversionPhaseR\x05phase\x12)\n\x10\x63urrent_progress\x18\x06 \x01(\x05R\x0f\x63urrentProgress\x12!\n\x0cmax_progress\x18\x07 \x01(\x05R\x0bmaxProgress\":\n\x13GetSlideDeckRequest\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\"U\n\x14GetSlideDeckResponse\x12=\n\nslide_deck\x18\x01 \x01(\x0b\x32\x1e.officeconvertapi.v1.SlideDeckR\tslideDeck\">\n\x17\x44\x65leteConversionRequest\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\"Y\n\x18\x44\x65leteConversionResponse\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\x12\x18\n\x07\x64\x65leted\x18\x02 \x01(\x08R\x07\x64\x65leted*\xb2\x01\n\x10\x43onversionStatus\x12!\n\x1d\x43ONVERSION_STATUS_UNSPECIFIED\x10\x00\x12\x1d\n\x19\x43ONVERSION_STATUS_PENDING\x10\x01\x12\x1d\n\x19\x43ONVERSION_STATUS_RUNNING\x10\x02\x12\x1f\n\x1b\x43ONVERSION_STATUS_SUCCEEDED\x10\x03\x12\x1c\n\x18\x43ONVERSION_STATUS_FAILED\x10\x04*\xe7\x01\n\x0f\x43onversionPhase\x12 \n\x1c\x43ONVERSION_PHASE_UNSPECIFIED\x10\x00\x12\x1d\n\x19\x43ONVERSION_PHASE_INACTIVE\x10\x01\x12%\n!CONVERSION_PHASE_EXTRACTING_NOTES\x10\x02\x12 \n\x1c\x43ONVERSION_PHASE_PPTX_TO_PDF\x10\x03\x12\"\n\x1e\x43ONVERSION_PHASE_PDF_TO_IMAGES\x10\x04\x12&\n\"CONVERSION_PHASE_UPLOADING_RESULTS\x10\x05\x32\xcc\x04\n\x11\x43onversionService\x12q\n\x10\x43reateConversion\x12,.officeconvertapi.v1.CreateConversionRequest\x1a-.officeconvertapi.v1.CreateConversionResponse\"\x00\x12n\n\x0fStartConversion\x12+.officeconvertapi.v1.StartConversionRequest\x1a,.officeconvertapi.v1.StartConversionResponse\"\x00\x12z\n\x13GetConversionStatus\x12/.officeconvertapi.v1.GetConversionStatusRequest\x1a\x30.officeconvertapi.v1.GetConversionStatusResponse\"\x00\x12\x65\n\x0cGetSlideDeck\x12(.officeconvertapi.v1.GetSlideDeckRequest\x1a).officeconvertapi.v1.GetSlideDeckResponse\"\x00\x12q\n\x10\x44\x65leteConversion\x12,.officeconvertapi.v1.DeleteConversionRequest\x1a-.officeconvertapi.v1.DeleteConversionResponse\"\x00\x42LZJgithub.com/end/officeconvert/gen/go/officeconvertapi/v1;officeconvertapiv1b\x06proto3') DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$officeconvertapi/v1/conversion.proto\x12\x13officeconvertapi.v1\x1a\x1fgoogle/protobuf/timestamp.proto\"[\n\x05Slide\x12\x14\n\x05index\x18\x01 \x01(\x05R\x05index\x12\x1f\n\x0bnotes_plain\x18\x02 \x01(\tR\nnotesPlain\x12\x1b\n\timage_url\x18\x03 \x01(\tR\x08imageUrl\"\xf6\x01\n\tSlideDeck\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\x12\'\n\x0fsource_filename\x18\x02 \x01(\tR\x0esourceFilename\x12\x32\n\x06slides\x18\x03 \x03(\x0b\x32\x1a.officeconvertapi.v1.SlideR\x06slides\x12\x39\n\ncreated_at\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\tcreatedAt\x12\x14\n\x05width\x18\x05 \x01(\x05R\x05width\x12\x16\n\x06height\x18\x06 \x01(\x05R\x06height\"\x8d\x01\n\x17\x43reateConversionRequest\x12\'\n\x0fsource_filename\x18\x01 \x01(\tR\x0esourceFilename\x12I\n\nresolution\x18\x02 \x01(\x0e\x32).officeconvertapi.v1.ConversionResolutionR\nresolution\"\xea\x01\n\x18\x43reateConversionResponse\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\x12#\n\rupload_bucket\x18\x02 \x01(\tR\x0cuploadBucket\x12*\n\x11upload_object_key\x18\x03 \x01(\tR\x0fuploadObjectKey\x12\x1d\n\nupload_url\x18\x04 \x01(\tR\tuploadUrl\x12\x39\n\nexpires_at\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\texpiresAt\"=\n\x16StartConversionRequest\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\"}\n\x17StartConversionResponse\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\x12=\n\x06status\x18\x02 \x01(\x0e\x32%.officeconvertapi.v1.ConversionStatusR\x06status\"A\n\x1aGetConversionStatusRequest\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\"\xeb\x02\n\x1bGetConversionStatusResponse\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\x12=\n\x06status\x18\x02 \x01(\x0e\x32%.officeconvertapi.v1.ConversionStatusR\x06status\x12#\n\rerror_message\x18\x03 \x01(\tR\x0c\x65rrorMessage\x12\x39\n\nupdated_at\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\tupdatedAt\x12:\n\x05phase\x18\x05 \x01(\x0e\x32$.officeconvertapi.v1.ConversionPhaseR\x05phase\x12)\n\x10\x63urrent_progress\x18\x06 \x01(\x05R\x0f\x63urrentProgress\x12!\n\x0cmax_progress\x18\x07 \x01(\x05R\x0bmaxProgress\":\n\x13GetSlideDeckRequest\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\"U\n\x14GetSlideDeckResponse\x12=\n\nslide_deck\x18\x01 \x01(\x0b\x32\x1e.officeconvertapi.v1.SlideDeckR\tslideDeck\">\n\x17\x44\x65leteConversionRequest\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\"Y\n\x18\x44\x65leteConversionResponse\x12#\n\rconversion_id\x18\x01 \x01(\tR\x0c\x63onversionId\x12\x18\n\x07\x64\x65leted\x18\x02 \x01(\x08R\x07\x64\x65leted*\xb2\x01\n\x10\x43onversionStatus\x12!\n\x1d\x43ONVERSION_STATUS_UNSPECIFIED\x10\x00\x12\x1d\n\x19\x43ONVERSION_STATUS_PENDING\x10\x01\x12\x1d\n\x19\x43ONVERSION_STATUS_RUNNING\x10\x02\x12\x1f\n\x1b\x43ONVERSION_STATUS_SUCCEEDED\x10\x03\x12\x1c\n\x18\x43ONVERSION_STATUS_FAILED\x10\x04*\xe7\x01\n\x0f\x43onversionPhase\x12 \n\x1c\x43ONVERSION_PHASE_UNSPECIFIED\x10\x00\x12\x1d\n\x19\x43ONVERSION_PHASE_INACTIVE\x10\x01\x12%\n!CONVERSION_PHASE_EXTRACTING_NOTES\x10\x02\x12 \n\x1c\x43ONVERSION_PHASE_PPTX_TO_PDF\x10\x03\x12\"\n\x1e\x43ONVERSION_PHASE_PDF_TO_IMAGES\x10\x04\x12&\n\"CONVERSION_PHASE_UPLOADING_RESULTS\x10\x05*\xd6\x01\n\x14\x43onversionResolution\x12%\n!CONVERSION_RESOLUTION_UNSPECIFIED\x10\x00\x12\x1c\n\x18\x43ONVERSION_RESOLUTION_SD\x10\x01\x12\x1c\n\x18\x43ONVERSION_RESOLUTION_HD\x10\x02\x12\x1d\n\x19\x43ONVERSION_RESOLUTION_FHD\x10\x03\x12\x1d\n\x19\x43ONVERSION_RESOLUTION_QHD\x10\x04\x12\x1d\n\x19\x43ONVERSION_RESOLUTION_UHD\x10\x05\x32\xcc\x04\n\x11\x43onversionService\x12q\n\x10\x43reateConversion\x12,.officeconvertapi.v1.CreateConversionRequest\x1a-.officeconvertapi.v1.CreateConversionResponse\"\x00\x12n\n\x0fStartConversion\x12+.officeconvertapi.v1.StartConversionRequest\x1a,.officeconvertapi.v1.StartConversionResponse\"\x00\x12z\n\x13GetConversionStatus\x12/.officeconvertapi.v1.GetConversionStatusRequest\x1a\x30.officeconvertapi.v1.GetConversionStatusResponse\"\x00\x12\x65\n\x0cGetSlideDeck\x12(.officeconvertapi.v1.GetSlideDeckRequest\x1a).officeconvertapi.v1.GetSlideDeckResponse\"\x00\x12q\n\x10\x44\x65leteConversion\x12,.officeconvertapi.v1.DeleteConversionRequest\x1a-.officeconvertapi.v1.DeleteConversionResponse\"\x00\x42LZJgithub.com/end/officeconvert/gen/go/officeconvertapi/v1;officeconvertapiv1b\x06proto3')
_globals = globals() _globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -33,34 +33,36 @@ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'officeconvertapi.v1.convers
if not _descriptor._USE_C_DESCRIPTORS: if not _descriptor._USE_C_DESCRIPTORS:
_globals['DESCRIPTOR']._loaded_options = None _globals['DESCRIPTOR']._loaded_options = None
_globals['DESCRIPTOR']._serialized_options = b'ZJgithub.com/end/officeconvert/gen/go/officeconvertapi/v1;officeconvertapiv1' _globals['DESCRIPTOR']._serialized_options = b'ZJgithub.com/end/officeconvert/gen/go/officeconvertapi/v1;officeconvertapiv1'
_globals['_CONVERSIONSTATUS']._serialized_start=1621 _globals['_CONVERSIONSTATUS']._serialized_start=1743
_globals['_CONVERSIONSTATUS']._serialized_end=1799 _globals['_CONVERSIONSTATUS']._serialized_end=1921
_globals['_CONVERSIONPHASE']._serialized_start=1802 _globals['_CONVERSIONPHASE']._serialized_start=1924
_globals['_CONVERSIONPHASE']._serialized_end=2033 _globals['_CONVERSIONPHASE']._serialized_end=2155
_globals['_CONVERSIONRESOLUTION']._serialized_start=2158
_globals['_CONVERSIONRESOLUTION']._serialized_end=2372
_globals['_SLIDE']._serialized_start=94 _globals['_SLIDE']._serialized_start=94
_globals['_SLIDE']._serialized_end=185 _globals['_SLIDE']._serialized_end=185
_globals['_SLIDEDECK']._serialized_start=188 _globals['_SLIDEDECK']._serialized_start=188
_globals['_SLIDEDECK']._serialized_end=388 _globals['_SLIDEDECK']._serialized_end=434
_globals['_CREATECONVERSIONREQUEST']._serialized_start=390 _globals['_CREATECONVERSIONREQUEST']._serialized_start=437
_globals['_CREATECONVERSIONREQUEST']._serialized_end=456 _globals['_CREATECONVERSIONREQUEST']._serialized_end=578
_globals['_CREATECONVERSIONRESPONSE']._serialized_start=459 _globals['_CREATECONVERSIONRESPONSE']._serialized_start=581
_globals['_CREATECONVERSIONRESPONSE']._serialized_end=693 _globals['_CREATECONVERSIONRESPONSE']._serialized_end=815
_globals['_STARTCONVERSIONREQUEST']._serialized_start=695 _globals['_STARTCONVERSIONREQUEST']._serialized_start=817
_globals['_STARTCONVERSIONREQUEST']._serialized_end=756 _globals['_STARTCONVERSIONREQUEST']._serialized_end=878
_globals['_STARTCONVERSIONRESPONSE']._serialized_start=758 _globals['_STARTCONVERSIONRESPONSE']._serialized_start=880
_globals['_STARTCONVERSIONRESPONSE']._serialized_end=883 _globals['_STARTCONVERSIONRESPONSE']._serialized_end=1005
_globals['_GETCONVERSIONSTATUSREQUEST']._serialized_start=885 _globals['_GETCONVERSIONSTATUSREQUEST']._serialized_start=1007
_globals['_GETCONVERSIONSTATUSREQUEST']._serialized_end=950 _globals['_GETCONVERSIONSTATUSREQUEST']._serialized_end=1072
_globals['_GETCONVERSIONSTATUSRESPONSE']._serialized_start=953 _globals['_GETCONVERSIONSTATUSRESPONSE']._serialized_start=1075
_globals['_GETCONVERSIONSTATUSRESPONSE']._serialized_end=1316 _globals['_GETCONVERSIONSTATUSRESPONSE']._serialized_end=1438
_globals['_GETSLIDEDECKREQUEST']._serialized_start=1318 _globals['_GETSLIDEDECKREQUEST']._serialized_start=1440
_globals['_GETSLIDEDECKREQUEST']._serialized_end=1376 _globals['_GETSLIDEDECKREQUEST']._serialized_end=1498
_globals['_GETSLIDEDECKRESPONSE']._serialized_start=1378 _globals['_GETSLIDEDECKRESPONSE']._serialized_start=1500
_globals['_GETSLIDEDECKRESPONSE']._serialized_end=1463 _globals['_GETSLIDEDECKRESPONSE']._serialized_end=1585
_globals['_DELETECONVERSIONREQUEST']._serialized_start=1465 _globals['_DELETECONVERSIONREQUEST']._serialized_start=1587
_globals['_DELETECONVERSIONREQUEST']._serialized_end=1527 _globals['_DELETECONVERSIONREQUEST']._serialized_end=1649
_globals['_DELETECONVERSIONRESPONSE']._serialized_start=1529 _globals['_DELETECONVERSIONRESPONSE']._serialized_start=1651
_globals['_DELETECONVERSIONRESPONSE']._serialized_end=1618 _globals['_DELETECONVERSIONRESPONSE']._serialized_end=1740
_globals['_CONVERSIONSERVICE']._serialized_start=2036 _globals['_CONVERSIONSERVICE']._serialized_start=2375
_globals['_CONVERSIONSERVICE']._serialized_end=2624 _globals['_CONVERSIONSERVICE']._serialized_end=2963
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)
@@ -26,6 +26,15 @@ class ConversionPhase(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
CONVERSION_PHASE_PPTX_TO_PDF: _ClassVar[ConversionPhase] CONVERSION_PHASE_PPTX_TO_PDF: _ClassVar[ConversionPhase]
CONVERSION_PHASE_PDF_TO_IMAGES: _ClassVar[ConversionPhase] CONVERSION_PHASE_PDF_TO_IMAGES: _ClassVar[ConversionPhase]
CONVERSION_PHASE_UPLOADING_RESULTS: _ClassVar[ConversionPhase] CONVERSION_PHASE_UPLOADING_RESULTS: _ClassVar[ConversionPhase]
class ConversionResolution(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
CONVERSION_RESOLUTION_UNSPECIFIED: _ClassVar[ConversionResolution]
CONVERSION_RESOLUTION_SD: _ClassVar[ConversionResolution]
CONVERSION_RESOLUTION_HD: _ClassVar[ConversionResolution]
CONVERSION_RESOLUTION_FHD: _ClassVar[ConversionResolution]
CONVERSION_RESOLUTION_QHD: _ClassVar[ConversionResolution]
CONVERSION_RESOLUTION_UHD: _ClassVar[ConversionResolution]
CONVERSION_STATUS_UNSPECIFIED: ConversionStatus CONVERSION_STATUS_UNSPECIFIED: ConversionStatus
CONVERSION_STATUS_PENDING: ConversionStatus CONVERSION_STATUS_PENDING: ConversionStatus
CONVERSION_STATUS_RUNNING: ConversionStatus CONVERSION_STATUS_RUNNING: ConversionStatus
@@ -37,6 +46,12 @@ CONVERSION_PHASE_EXTRACTING_NOTES: ConversionPhase
CONVERSION_PHASE_PPTX_TO_PDF: ConversionPhase CONVERSION_PHASE_PPTX_TO_PDF: ConversionPhase
CONVERSION_PHASE_PDF_TO_IMAGES: ConversionPhase CONVERSION_PHASE_PDF_TO_IMAGES: ConversionPhase
CONVERSION_PHASE_UPLOADING_RESULTS: ConversionPhase CONVERSION_PHASE_UPLOADING_RESULTS: ConversionPhase
CONVERSION_RESOLUTION_UNSPECIFIED: ConversionResolution
CONVERSION_RESOLUTION_SD: ConversionResolution
CONVERSION_RESOLUTION_HD: ConversionResolution
CONVERSION_RESOLUTION_FHD: ConversionResolution
CONVERSION_RESOLUTION_QHD: ConversionResolution
CONVERSION_RESOLUTION_UHD: ConversionResolution
class Slide(_message.Message): class Slide(_message.Message):
__slots__ = ("index", "notes_plain", "image_url") __slots__ = ("index", "notes_plain", "image_url")
@@ -49,22 +64,28 @@ class Slide(_message.Message):
def __init__(self, index: _Optional[int] = ..., notes_plain: _Optional[str] = ..., image_url: _Optional[str] = ...) -> None: ... def __init__(self, index: _Optional[int] = ..., notes_plain: _Optional[str] = ..., image_url: _Optional[str] = ...) -> None: ...
class SlideDeck(_message.Message): class SlideDeck(_message.Message):
__slots__ = ("conversion_id", "source_filename", "slides", "created_at") __slots__ = ("conversion_id", "source_filename", "slides", "created_at", "width", "height")
CONVERSION_ID_FIELD_NUMBER: _ClassVar[int] CONVERSION_ID_FIELD_NUMBER: _ClassVar[int]
SOURCE_FILENAME_FIELD_NUMBER: _ClassVar[int] SOURCE_FILENAME_FIELD_NUMBER: _ClassVar[int]
SLIDES_FIELD_NUMBER: _ClassVar[int] SLIDES_FIELD_NUMBER: _ClassVar[int]
CREATED_AT_FIELD_NUMBER: _ClassVar[int] CREATED_AT_FIELD_NUMBER: _ClassVar[int]
WIDTH_FIELD_NUMBER: _ClassVar[int]
HEIGHT_FIELD_NUMBER: _ClassVar[int]
conversion_id: str conversion_id: str
source_filename: str source_filename: str
slides: _containers.RepeatedCompositeFieldContainer[Slide] slides: _containers.RepeatedCompositeFieldContainer[Slide]
created_at: _timestamp_pb2.Timestamp created_at: _timestamp_pb2.Timestamp
def __init__(self, conversion_id: _Optional[str] = ..., source_filename: _Optional[str] = ..., slides: _Optional[_Iterable[_Union[Slide, _Mapping]]] = ..., created_at: _Optional[_Union[datetime.datetime, _timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ... width: int
height: int
def __init__(self, conversion_id: _Optional[str] = ..., source_filename: _Optional[str] = ..., slides: _Optional[_Iterable[_Union[Slide, _Mapping]]] = ..., created_at: _Optional[_Union[datetime.datetime, _timestamp_pb2.Timestamp, _Mapping]] = ..., width: _Optional[int] = ..., height: _Optional[int] = ...) -> None: ...
class CreateConversionRequest(_message.Message): class CreateConversionRequest(_message.Message):
__slots__ = ("source_filename",) __slots__ = ("source_filename", "resolution")
SOURCE_FILENAME_FIELD_NUMBER: _ClassVar[int] SOURCE_FILENAME_FIELD_NUMBER: _ClassVar[int]
RESOLUTION_FIELD_NUMBER: _ClassVar[int]
source_filename: str source_filename: str
def __init__(self, source_filename: _Optional[str] = ...) -> None: ... resolution: ConversionResolution
def __init__(self, source_filename: _Optional[str] = ..., resolution: _Optional[_Union[ConversionResolution, str]] = ...) -> None: ...
class CreateConversionResponse(_message.Message): class CreateConversionResponse(_message.Message):
__slots__ = ("conversion_id", "upload_bucket", "upload_object_key", "upload_url", "expires_at") __slots__ = ("conversion_id", "upload_bucket", "upload_object_key", "upload_url", "expires_at")
@@ -43,6 +43,16 @@ enum ConversionPhase {
CONVERSION_PHASE_UPLOADING_RESULTS = 5; CONVERSION_PHASE_UPLOADING_RESULTS = 5;
} }
// ConversionResolution represents preset output quality targets.
enum ConversionResolution {
CONVERSION_RESOLUTION_UNSPECIFIED = 0;
CONVERSION_RESOLUTION_SD = 1;
CONVERSION_RESOLUTION_HD = 2;
CONVERSION_RESOLUTION_FHD = 3;
CONVERSION_RESOLUTION_QHD = 4;
CONVERSION_RESOLUTION_UHD = 5;
}
// Slide contains extracted notes and the rendered image URL for one slide. // Slide contains extracted notes and the rendered image URL for one slide.
message Slide { message Slide {
int32 index = 1; int32 index = 1;
@@ -56,11 +66,14 @@ message SlideDeck {
string source_filename = 2; string source_filename = 2;
repeated Slide slides = 3; repeated Slide slides = 3;
google.protobuf.Timestamp created_at = 4; google.protobuf.Timestamp created_at = 4;
int32 width = 5;
int32 height = 6;
} }
// CreateConversionRequest starts a conversion session. // CreateConversionRequest starts a conversion session.
message CreateConversionRequest { message CreateConversionRequest {
string source_filename = 1; string source_filename = 1;
ConversionResolution resolution = 2;
} }
// CreateConversionResponse returns upload details for the session. // CreateConversionResponse returns upload details for the session.
@@ -5,6 +5,7 @@ from __future__ import annotations
from collections.abc import Callable from collections.abc import Callable
from dataclasses import dataclass from dataclasses import dataclass
import logging import logging
import math
from pathlib import Path from pathlib import Path
import subprocess import subprocess
from typing import Iterable from typing import Iterable
@@ -27,6 +28,12 @@ class SlideDeckResult:
source_filename: str source_filename: str
slides: list[SlideArtifact] slides: list[SlideArtifact]
width: int
height: int
inferred_dpi: int
pptx_to_pdf_timeout_s: int
pdf_to_images_timeout_s: int
pdf_to_images_page_timeout_s: int
ProgressCallback = Callable[[str, int, int], None] ProgressCallback = Callable[[str, int, int], None]
@@ -36,6 +43,21 @@ PHASE_EXTRACTING_NOTES = "extracting_notes"
PHASE_PPTX_TO_PDF = "pptx_to_pdf" PHASE_PPTX_TO_PDF = "pptx_to_pdf"
PHASE_PDF_TO_IMAGES = "pdf_to_images" PHASE_PDF_TO_IMAGES = "pdf_to_images"
RESOLUTION_SD = "sd"
RESOLUTION_HD = "hd"
RESOLUTION_FHD = "fhd"
RESOLUTION_QHD = "qhd"
RESOLUTION_UHD = "uhd"
_SHORT_EDGE_PIXELS_BY_RESOLUTION = {
RESOLUTION_SD: 480,
RESOLUTION_HD: 720,
RESOLUTION_FHD: 1080,
RESOLUTION_QHD: 1440,
RESOLUTION_UHD: 2160,
}
_EMU_PER_INCH = 914400
logger = logging.getLogger("uvicorn.error") logger = logging.getLogger("uvicorn.error")
@@ -108,6 +130,8 @@ def render_pdf_to_images(
out_dir: Path, out_dir: Path,
*, *,
dpi: int = 72, dpi: int = 72,
target_width: int | None = None,
target_height: int | None = None,
image_format: str = "png", image_format: str = "png",
timeout_s: int = 120, timeout_s: int = 120,
total_pages: int | None = None, total_pages: int | None = None,
@@ -132,14 +156,24 @@ def render_pdf_to_images(
""" """
if not pdf_path.exists(): if not pdf_path.exists():
raise FileNotFoundError(f"source PDF does not exist: {pdf_path}") raise FileNotFoundError(f"source PDF does not exist: {pdf_path}")
if (target_width is None) != (target_height is None):
raise ValueError("target_width and target_height must be provided together")
if target_width is not None and target_width <= 0:
raise ValueError("target_width must be greater than zero")
if target_height is not None and target_height <= 0:
raise ValueError("target_height must be greater than zero")
out_dir.mkdir(parents=True, exist_ok=True) out_dir.mkdir(parents=True, exist_ok=True)
scale_args: list[str] = []
if target_width is not None and target_height is not None:
scale_args = ["-scale-to-x", str(target_width), "-scale-to-y", str(target_height)]
if total_pages is None: if total_pages is None:
prefix_path = out_dir / "slide" prefix_path = out_dir / "slide"
command = [ command = [
"pdftoppm", "pdftoppm",
"-r", "-r",
str(dpi), str(dpi),
*scale_args,
f"-{image_format}", f"-{image_format}",
str(pdf_path.resolve()), str(pdf_path.resolve()),
str(prefix_path), str(prefix_path),
@@ -156,7 +190,7 @@ def render_pdf_to_images(
message = ( message = (
"Poppler rasterization timed out after " "Poppler rasterization timed out after "
f"{timeout_s} seconds while rendering {pdf_path.name}; " f"{timeout_s} seconds while rendering {pdf_path.name}; "
"increase conversion PDF render timeout cap or lower image DPI" "increase conversion PDF render timeout cap or lower output resolution"
) )
logger.error(message, exc_info=True) logger.error(message, exc_info=True)
raise ConversionTimeoutError(message) from exc raise ConversionTimeoutError(message) from exc
@@ -175,6 +209,7 @@ def render_pdf_to_images(
"pdftoppm", "pdftoppm",
"-r", "-r",
str(dpi), str(dpi),
*scale_args,
f"-{image_format}", f"-{image_format}",
"-f", "-f",
str(page_index), str(page_index),
@@ -202,7 +237,7 @@ def render_pdf_to_images(
message = ( message = (
"Poppler rasterization timed out while rendering page " "Poppler rasterization timed out while rendering page "
f"{page_index}/{total_pages} of {pdf_path.name}; " f"{page_index}/{total_pages} of {pdf_path.name}; "
f"{timeout_context}. Increase timeout settings or lower image DPI." f"{timeout_context}. Increase timeout settings or lower output resolution."
) )
logger.error(message, exc_info=True) logger.error(message, exc_info=True)
raise ConversionTimeoutError(message) from exc raise ConversionTimeoutError(message) from exc
@@ -254,7 +289,7 @@ def convert_pptx_to_slidedeck(
pptx_path: Path, pptx_path: Path,
work_dir: Path, work_dir: Path,
*, *,
dpi: int = 72, resolution: str = RESOLUTION_FHD,
image_format: str = "png", image_format: str = "png",
pptx_to_pdf_timeout_s: int = 180, pptx_to_pdf_timeout_s: int = 180,
pdf_to_images_timeout_s: int = 1800, pdf_to_images_timeout_s: int = 1800,
@@ -273,7 +308,7 @@ def convert_pptx_to_slidedeck(
Args: Args:
pptx_path: Source `.pptx` path. pptx_path: Source `.pptx` path.
work_dir: Scratch directory for generated outputs. work_dir: Scratch directory for generated outputs.
dpi: Rasterization DPI for output slide images. resolution: Output resolution preset (`sd`, `hd`, `fhd`, `qhd`, `uhd`).
image_format: Output image format accepted by `pdftoppm`. image_format: Output image format accepted by `pdftoppm`.
pptx_to_pdf_timeout_s: Timeout in seconds for the LibreOffice subprocess. pptx_to_pdf_timeout_s: Timeout in seconds for the LibreOffice subprocess.
pdf_to_images_timeout_s: Timeout in seconds for the Poppler subprocess. pdf_to_images_timeout_s: Timeout in seconds for the Poppler subprocess.
@@ -292,6 +327,18 @@ def convert_pptx_to_slidedeck(
_emit_progress(progress_callback, PHASE_EXTRACTING_NOTES, 0, 1) _emit_progress(progress_callback, PHASE_EXTRACTING_NOTES, 0, 1)
notes = extract_slide_notes(pptx_path) notes = extract_slide_notes(pptx_path)
_emit_progress(progress_callback, PHASE_EXTRACTING_NOTES, 1, 1) _emit_progress(progress_callback, PHASE_EXTRACTING_NOTES, 1, 1)
slide_width, slide_height = _read_slide_size_emu(pptx_path)
output_width, output_height = _infer_output_dimensions_from_slide_size(
slide_width=slide_width,
slide_height=slide_height,
resolution=resolution,
)
inferred_dpi = infer_minimum_raster_dpi(
slide_width_emu=slide_width,
slide_height_emu=slide_height,
output_width_px=output_width,
output_height_px=output_height,
)
slide_count = len(notes) slide_count = len(notes)
pptx_to_pdf_timeout = _compute_adaptive_timeout( pptx_to_pdf_timeout = _compute_adaptive_timeout(
slide_count=slide_count, slide_count=slide_count,
@@ -317,12 +364,16 @@ def convert_pptx_to_slidedeck(
base_timeout_s=pdf_to_images_base_timeout_s, base_timeout_s=pdf_to_images_base_timeout_s,
) )
logger.info( logger.info(
"Conversion plan source=%s slides=%d dpi=%d image_format=%s " "Conversion plan source=%s slides=%d inferred_dpi=%d image_format=%s "
"resolution=%s output_size=%dx%d "
"computed_timeouts_s[pptx_to_pdf_total=%d,pdf_to_images_total=%d,pdf_to_images_per_page=%d]", "computed_timeouts_s[pptx_to_pdf_total=%d,pdf_to_images_total=%d,pdf_to_images_per_page=%d]",
pptx_path.name, pptx_path.name,
slide_count, slide_count,
dpi, inferred_dpi,
image_format, image_format,
resolution,
output_width,
output_height,
pptx_to_pdf_timeout, pptx_to_pdf_timeout,
pdf_to_images_timeout, pdf_to_images_timeout,
pdf_to_images_page_timeout, pdf_to_images_page_timeout,
@@ -330,7 +381,9 @@ def convert_pptx_to_slidedeck(
image_paths = render_pdf_to_images( image_paths = render_pdf_to_images(
pdf_path, pdf_path,
image_dir, image_dir,
dpi=dpi, dpi=inferred_dpi,
target_width=output_width,
target_height=output_height,
image_format=image_format, image_format=image_format,
timeout_s=pdf_to_images_page_timeout, timeout_s=pdf_to_images_page_timeout,
total_pages=slide_count, total_pages=slide_count,
@@ -353,7 +406,82 @@ def convert_pptx_to_slidedeck(
SlideArtifact(index=index, image_path=image_path, notes_plain=note) SlideArtifact(index=index, image_path=image_path, notes_plain=note)
for index, (image_path, note) in enumerate(zip(image_paths, notes), start=1) for index, (image_path, note) in enumerate(zip(image_paths, notes), start=1)
] ]
return SlideDeckResult(source_filename=pptx_path.name, slides=slides) return SlideDeckResult(
source_filename=pptx_path.name,
slides=slides,
width=output_width,
height=output_height,
inferred_dpi=inferred_dpi,
pptx_to_pdf_timeout_s=pptx_to_pdf_timeout,
pdf_to_images_timeout_s=pdf_to_images_timeout,
pdf_to_images_page_timeout_s=pdf_to_images_page_timeout,
)
def infer_output_dimensions_for_resolution(
pptx_path: Path,
*,
resolution: str,
) -> tuple[int, int]:
"""Infer output image dimensions from source slide aspect ratio and preset."""
slide_width, slide_height = _read_slide_size_emu(pptx_path)
return _infer_output_dimensions_from_slide_size(
slide_width=slide_width,
slide_height=slide_height,
resolution=resolution,
)
def infer_minimum_raster_dpi(
*,
slide_width_emu: int,
slide_height_emu: int,
output_width_px: int,
output_height_px: int,
) -> int:
"""Compute the minimum DPI needed to reach target output dimensions."""
if slide_width_emu <= 0 or slide_height_emu <= 0:
raise ValueError("source slide dimensions must be greater than zero")
if output_width_px <= 0 or output_height_px <= 0:
raise ValueError("output dimensions must be greater than zero")
dpi_for_width = (output_width_px * _EMU_PER_INCH) / slide_width_emu
dpi_for_height = (output_height_px * _EMU_PER_INCH) / slide_height_emu
return max(1, math.ceil(max(dpi_for_width, dpi_for_height)))
def _read_slide_size_emu(pptx_path: Path) -> tuple[int, int]:
"""Read presentation slide size in English Metric Units (EMU)."""
if not pptx_path.exists():
raise FileNotFoundError(f"source PPTX does not exist: {pptx_path}")
presentation = Presentation(str(pptx_path.resolve()))
# Canonical python-pptx API on `Presentation` object.
slide_width = presentation.slide_width
slide_height = presentation.slide_height
if slide_width is None or slide_height is None:
raise ValueError("source presentation did not define slide dimensions")
slide_width = int(slide_width)
slide_height = int(slide_height)
if slide_width <= 0 or slide_height <= 0:
raise ValueError("source slide dimensions must be greater than zero")
return slide_width, slide_height
def _infer_output_dimensions_from_slide_size(
*,
slide_width: int,
slide_height: int,
resolution: str,
) -> tuple[int, int]:
"""Infer output dimensions from slide size and short-edge preset."""
normalized = resolution.strip().lower()
short_edge_pixels = _SHORT_EDGE_PIXELS_BY_RESOLUTION.get(normalized)
if short_edge_pixels is None:
raise ValueError(f"unsupported resolution preset: {resolution}")
if slide_width >= slide_height:
long_edge = max(1, round(short_edge_pixels * (slide_width / slide_height)))
return long_edge, short_edge_pixels
long_edge = max(1, round(short_edge_pixels * (slide_height / slide_width)))
return short_edge_pixels, long_edge
def _compute_adaptive_timeout( def _compute_adaptive_timeout(
@@ -16,7 +16,6 @@ class ServerConfig:
s3_secure: bool s3_secure: bool
s3_public_endpoint: str s3_public_endpoint: str
s3_session_ttl_seconds: int s3_session_ttl_seconds: int
conversion_image_dpi: int
conversion_pptx_to_pdf_timeout_seconds: int conversion_pptx_to_pdf_timeout_seconds: int
conversion_pdf_to_images_timeout_seconds: int conversion_pdf_to_images_timeout_seconds: int
conversion_pptx_to_pdf_base_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_secure=os.getenv("S3_USE_SSL", "false").lower() == "true",
s3_public_endpoint=os.getenv("S3_PUBLIC_ENDPOINT", "localhost:8333"), s3_public_endpoint=os.getenv("S3_PUBLIC_ENDPOINT", "localhost:8333"),
s3_session_ttl_seconds=int(os.getenv("S3_SESSION_TTL_SECONDS", "3600")), 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( conversion_pptx_to_pdf_timeout_seconds=int(
os.getenv("CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS", "180") os.getenv("CONVERSION_PPTX_TO_PDF_TIMEOUT_SECONDS", "180")
), ),
@@ -19,6 +19,7 @@ class ConversionSession:
conversion_id: str conversion_id: str
source_filename: str source_filename: str
resolution: conversion_pb2.ConversionResolution
bucket_name: str bucket_name: str
upload_object_key: str upload_object_key: str
status: conversion_pb2.ConversionStatus status: conversion_pb2.ConversionStatus
@@ -22,6 +22,11 @@ from officeconvert.conversion import (
PHASE_EXTRACTING_NOTES, PHASE_EXTRACTING_NOTES,
PHASE_PDF_TO_IMAGES, PHASE_PDF_TO_IMAGES,
PHASE_PPTX_TO_PDF, PHASE_PPTX_TO_PDF,
RESOLUTION_FHD,
RESOLUTION_HD,
RESOLUTION_QHD,
RESOLUTION_SD,
RESOLUTION_UHD,
) )
from officeconvertapi.v1 import conversion_connect, conversion_pb2 from officeconvertapi.v1 import conversion_connect, conversion_pb2
@@ -31,6 +36,14 @@ from officeconvert_server.storage import S3Store
logger = logging.getLogger("uvicorn.error") 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): class ConversionServiceImpl(conversion_connect.ConversionService):
"""Implements the conversion API with in-memory state and S3 orchestration.""" """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") raise ConnectError(Code.INVALID_ARGUMENT, "source_filename is required")
if not source_filename.lower().endswith(".pptx"): if not source_filename.lower().endswith(".pptx"):
raise ConnectError(Code.INVALID_ARGUMENT, "only .pptx input is supported") 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()) conversion_id = str(uuid.uuid4())
bucket_name = f"oc-{conversion_id}" bucket_name = f"oc-{conversion_id}"
@@ -70,6 +88,7 @@ class ConversionServiceImpl(conversion_connect.ConversionService):
session = ConversionSession( session = ConversionSession(
conversion_id=conversion_id, conversion_id=conversion_id,
source_filename=source_filename, source_filename=source_filename,
resolution=resolution,
bucket_name=bucket_name, bucket_name=bucket_name,
upload_object_key=upload_key, upload_object_key=upload_key,
status=conversion_pb2.CONVERSION_STATUS_PENDING, status=conversion_pb2.CONVERSION_STATUS_PENDING,
@@ -186,11 +205,11 @@ class ConversionServiceImpl(conversion_connect.ConversionService):
"""Execute conversion flow and persist terminal state in memory.""" """Execute conversion flow and persist terminal state in memory."""
started_at = time.monotonic() started_at = time.monotonic()
logger.info( 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]", "timeout_caps_s[pptx_to_pdf_total=%d,pdf_to_images_total=%d]",
session.conversion_id, session.conversion_id,
session.source_filename, 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_pptx_to_pdf_timeout_seconds,
self._config.conversion_pdf_to_images_timeout_seconds, self._config.conversion_pdf_to_images_timeout_seconds,
) )
@@ -210,7 +229,7 @@ class ConversionServiceImpl(conversion_connect.ConversionService):
convert_pptx_to_slidedeck, convert_pptx_to_slidedeck,
source_path, source_path,
work_dir, 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, 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, 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, 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, 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( self._set_session_progress(
session, session,
phase=conversion_pb2.CONVERSION_PHASE_UPLOADING_RESULTS, phase=conversion_pb2.CONVERSION_PHASE_UPLOADING_RESULTS,
@@ -235,6 +268,8 @@ class ConversionServiceImpl(conversion_connect.ConversionService):
session, session,
result.slides, result.slides,
result.source_filename, result.source_filename,
result.width,
result.height,
lambda current, max_value: self._set_session_progress( lambda current, max_value: self._set_session_progress(
session, session,
phase=conversion_pb2.CONVERSION_PHASE_UPLOADING_RESULTS, phase=conversion_pb2.CONVERSION_PHASE_UPLOADING_RESULTS,
@@ -300,6 +335,8 @@ class ConversionServiceImpl(conversion_connect.ConversionService):
session: ConversionSession, session: ConversionSession,
slides: list[SlideArtifact], slides: list[SlideArtifact],
source_filename: str, source_filename: str,
width: int,
height: int,
progress_callback: Callable[[int, int], None] | None = None, progress_callback: Callable[[int, int], None] | None = None,
) -> conversion_pb2.SlideDeck: ) -> conversion_pb2.SlideDeck:
"""Upload generated slide images and construct API response payload.""" """Upload generated slide images and construct API response payload."""
@@ -328,6 +365,8 @@ class ConversionServiceImpl(conversion_connect.ConversionService):
source_filename=source_filename, source_filename=source_filename,
slides=response_slides, slides=response_slides,
created_at=_to_timestamp(utc_now()), created_at=_to_timestamp(utc_now()),
width=width,
height=height,
) )
async def _delayed_cleanup(self, session: ConversionSession) -> None: async def _delayed_cleanup(self, session: ConversionSession) -> None: