allow specifying conversion resolution, drop explicit dpi
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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}"; \
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user