From 06d4122e4ef97931193b6b787b815d5753613081 Mon Sep 17 00:00:00 2001 From: Elijah Duffy Date: Thu, 7 May 2026 10:35:37 -0700 Subject: [PATCH] add rich output support for slide notes --- clients/go/officeconvertclient/client.go | 42 ++ gen/go/officeconvertapi/v1/conversion.pb.go | 420 ++++++++++++++---- .../officeconvertapi/v1/conversion_connect.py | 12 +- .../officeconvertapi/v1/conversion_pb2.py | 72 +-- .../officeconvertapi/v1/conversion_pb2.pyi | 47 +- proto/officeconvertapi/v1/conversion.proto | 30 ++ .../src/officeconvert/__init__.py | 8 + .../src/officeconvert/conversion.py | 191 +++++++- .../officeconvert/tests/test_notes_html.py | 111 +++++ .../server/src/officeconvert_server/models.py | 1 + .../src/officeconvert_server/service.py | 37 ++ 11 files changed, 831 insertions(+), 140 deletions(-) create mode 100644 python/packages/officeconvert/tests/test_notes_html.py diff --git a/clients/go/officeconvertclient/client.go b/clients/go/officeconvertclient/client.go index b5c94ce..b50def0 100644 --- a/clients/go/officeconvertclient/client.go +++ b/clients/go/officeconvertclient/client.go @@ -21,10 +21,28 @@ type RasterTierOptions struct { JPEGQuality int32 } +// HtmlFormattingPolicy configures which formatting features are ignored in HTML notes mode. +type HtmlFormattingPolicy struct { + IgnoreBold bool + IgnoreItalic bool + IgnoreUnderline bool + IgnoreStrikethrough bool + IgnoreFontSize bool + IgnoreColor bool +} + +// NotesOptions controls speaker-notes extraction/output. +type NotesOptions struct { + Format officeconvertapiv1.NotesFormat + HTMLUseParagraphTags *bool + HTMLPolicy *HtmlFormattingPolicy +} + // CreateConversionOptions configures optional full and thumbnail raster tiers. type CreateConversionOptions struct { Full *RasterTierOptions Thumbnail *RasterTierOptions + Notes *NotesOptions } // Client wraps the generated Connect client with orchestration-focused helpers. @@ -67,6 +85,7 @@ func (c *Client) CreateConversion( if options != nil { message.Full = toProtoSlideRasterOptions(options.Full) message.Thumbnail = toProtoSlideRasterOptions(options.Thumbnail) + message.Notes = toProtoNotesOptions(options.Notes) } req := connect.NewRequest(message) res, err := c.rpc.CreateConversion(ctx, req) @@ -95,6 +114,29 @@ func toProtoSlideRasterOptions( return proto } +func toProtoNotesOptions(options *NotesOptions) *officeconvertapiv1.NotesOptions { + if options == nil { + return nil + } + proto := &officeconvertapiv1.NotesOptions{ + Format: options.Format, + } + if options.HTMLUseParagraphTags != nil { + proto.HtmlUseParagraphTags = options.HTMLUseParagraphTags + } + if options.HTMLPolicy != nil { + proto.HtmlPolicy = &officeconvertapiv1.HtmlFormattingPolicy{ + IgnoreBold: options.HTMLPolicy.IgnoreBold, + IgnoreItalic: options.HTMLPolicy.IgnoreItalic, + IgnoreUnderline: options.HTMLPolicy.IgnoreUnderline, + IgnoreStrikethrough: options.HTMLPolicy.IgnoreStrikethrough, + IgnoreFontSize: options.HTMLPolicy.IgnoreFontSize, + IgnoreColor: options.HTMLPolicy.IgnoreColor, + } + } + return proto +} + // StartConversion signals that upload is complete and conversion can begin. func (c *Client) StartConversion( ctx context.Context, diff --git a/gen/go/officeconvertapi/v1/conversion.pb.go b/gen/go/officeconvertapi/v1/conversion.pb.go index 32393d7..37700d4 100644 --- a/gen/go/officeconvertapi/v1/conversion.pb.go +++ b/gen/go/officeconvertapi/v1/conversion.pb.go @@ -196,6 +196,56 @@ func (ConversionResolution) EnumDescriptor() ([]byte, []int) { return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{2} } +// NotesFormat controls what note representation the server should compute. +type NotesFormat int32 + +const ( + NotesFormat_NOTES_FORMAT_UNSPECIFIED NotesFormat = 0 + NotesFormat_NOTES_FORMAT_PLAIN NotesFormat = 1 + NotesFormat_NOTES_FORMAT_HTML NotesFormat = 2 +) + +// Enum value maps for NotesFormat. +var ( + NotesFormat_name = map[int32]string{ + 0: "NOTES_FORMAT_UNSPECIFIED", + 1: "NOTES_FORMAT_PLAIN", + 2: "NOTES_FORMAT_HTML", + } + NotesFormat_value = map[string]int32{ + "NOTES_FORMAT_UNSPECIFIED": 0, + "NOTES_FORMAT_PLAIN": 1, + "NOTES_FORMAT_HTML": 2, + } +) + +func (x NotesFormat) Enum() *NotesFormat { + p := new(NotesFormat) + *p = x + return p +} + +func (x NotesFormat) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (NotesFormat) Descriptor() protoreflect.EnumDescriptor { + return file_officeconvertapi_v1_conversion_proto_enumTypes[3].Descriptor() +} + +func (NotesFormat) Type() protoreflect.EnumType { + return &file_officeconvertapi_v1_conversion_proto_enumTypes[3] +} + +func (x NotesFormat) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use NotesFormat.Descriptor instead. +func (NotesFormat) EnumDescriptor() ([]byte, []int) { + return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{3} +} + // JpegOutputOptions configures JPEG-specific encoding controls. type JpegOutputOptions struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -318,6 +368,155 @@ type SlideRasterOptions_Jpeg struct { func (*SlideRasterOptions_Jpeg) isSlideRasterOptions_Format() {} +// HtmlFormattingPolicy configures which formatting features are ignored in HTML mode. +type HtmlFormattingPolicy struct { + state protoimpl.MessageState `protogen:"open.v1"` + IgnoreBold bool `protobuf:"varint,1,opt,name=ignore_bold,json=ignoreBold,proto3" json:"ignore_bold,omitempty"` + IgnoreItalic bool `protobuf:"varint,2,opt,name=ignore_italic,json=ignoreItalic,proto3" json:"ignore_italic,omitempty"` + IgnoreUnderline bool `protobuf:"varint,3,opt,name=ignore_underline,json=ignoreUnderline,proto3" json:"ignore_underline,omitempty"` + IgnoreStrikethrough bool `protobuf:"varint,4,opt,name=ignore_strikethrough,json=ignoreStrikethrough,proto3" json:"ignore_strikethrough,omitempty"` + IgnoreFontSize bool `protobuf:"varint,5,opt,name=ignore_font_size,json=ignoreFontSize,proto3" json:"ignore_font_size,omitempty"` + IgnoreColor bool `protobuf:"varint,6,opt,name=ignore_color,json=ignoreColor,proto3" json:"ignore_color,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HtmlFormattingPolicy) Reset() { + *x = HtmlFormattingPolicy{} + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HtmlFormattingPolicy) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HtmlFormattingPolicy) ProtoMessage() {} + +func (x *HtmlFormattingPolicy) ProtoReflect() protoreflect.Message { + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HtmlFormattingPolicy.ProtoReflect.Descriptor instead. +func (*HtmlFormattingPolicy) Descriptor() ([]byte, []int) { + return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{2} +} + +func (x *HtmlFormattingPolicy) GetIgnoreBold() bool { + if x != nil { + return x.IgnoreBold + } + return false +} + +func (x *HtmlFormattingPolicy) GetIgnoreItalic() bool { + if x != nil { + return x.IgnoreItalic + } + return false +} + +func (x *HtmlFormattingPolicy) GetIgnoreUnderline() bool { + if x != nil { + return x.IgnoreUnderline + } + return false +} + +func (x *HtmlFormattingPolicy) GetIgnoreStrikethrough() bool { + if x != nil { + return x.IgnoreStrikethrough + } + return false +} + +func (x *HtmlFormattingPolicy) GetIgnoreFontSize() bool { + if x != nil { + return x.IgnoreFontSize + } + return false +} + +func (x *HtmlFormattingPolicy) GetIgnoreColor() bool { + if x != nil { + return x.IgnoreColor + } + return false +} + +// NotesOptions configures note extraction behavior. +type NotesOptions struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Output format for extracted notes. + Format NotesFormat `protobuf:"varint,1,opt,name=format,proto3,enum=officeconvertapi.v1.NotesFormat" json:"format,omitempty"` + // If true, wrap PPTX paragraphs as

blocks in HTML mode. If false, emit
only. + HtmlUseParagraphTags *bool `protobuf:"varint,2,opt,name=html_use_paragraph_tags,json=htmlUseParagraphTags,proto3,oneof" json:"html_use_paragraph_tags,omitempty"` + // Formatting policy for HTML mode. + HtmlPolicy *HtmlFormattingPolicy `protobuf:"bytes,3,opt,name=html_policy,json=htmlPolicy,proto3" json:"html_policy,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NotesOptions) Reset() { + *x = NotesOptions{} + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NotesOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotesOptions) ProtoMessage() {} + +func (x *NotesOptions) ProtoReflect() protoreflect.Message { + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotesOptions.ProtoReflect.Descriptor instead. +func (*NotesOptions) Descriptor() ([]byte, []int) { + return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{3} +} + +func (x *NotesOptions) GetFormat() NotesFormat { + if x != nil { + return x.Format + } + return NotesFormat_NOTES_FORMAT_UNSPECIFIED +} + +func (x *NotesOptions) GetHtmlUseParagraphTags() bool { + if x != nil && x.HtmlUseParagraphTags != nil { + return *x.HtmlUseParagraphTags + } + return false +} + +func (x *NotesOptions) GetHtmlPolicy() *HtmlFormattingPolicy { + if x != nil { + return x.HtmlPolicy + } + return nil +} + // Slide contains extracted notes and the rendered image URL for one slide. type Slide struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -327,13 +526,15 @@ type Slide struct { ImageUrl string `protobuf:"bytes,3,opt,name=image_url,json=imageUrl,proto3" json:"image_url,omitempty"` // Thumbnail rendered image URL. ThumbnailImageUrl string `protobuf:"bytes,4,opt,name=thumbnail_image_url,json=thumbnailImageUrl,proto3" json:"thumbnail_image_url,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Optional, sanitized HTML version of notes when requested. + NotesHtml string `protobuf:"bytes,5,opt,name=notes_html,json=notesHtml,proto3" json:"notes_html,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Slide) Reset() { *x = Slide{} - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[2] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -345,7 +546,7 @@ func (x *Slide) String() string { func (*Slide) ProtoMessage() {} func (x *Slide) ProtoReflect() protoreflect.Message { - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[2] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -358,7 +559,7 @@ func (x *Slide) ProtoReflect() protoreflect.Message { // Deprecated: Use Slide.ProtoReflect.Descriptor instead. func (*Slide) Descriptor() ([]byte, []int) { - return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{2} + return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{4} } func (x *Slide) GetIndex() int32 { @@ -389,6 +590,13 @@ func (x *Slide) GetThumbnailImageUrl() string { return "" } +func (x *Slide) GetNotesHtml() string { + if x != nil { + return x.NotesHtml + } + return "" +} + // SlideDeck is the final structured conversion artifact. type SlideDeck struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -411,7 +619,7 @@ type SlideDeck struct { func (x *SlideDeck) Reset() { *x = SlideDeck{} - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[3] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -423,7 +631,7 @@ func (x *SlideDeck) String() string { func (*SlideDeck) ProtoMessage() {} func (x *SlideDeck) ProtoReflect() protoreflect.Message { - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[3] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -436,7 +644,7 @@ func (x *SlideDeck) ProtoReflect() protoreflect.Message { // Deprecated: Use SlideDeck.ProtoReflect.Descriptor instead. func (*SlideDeck) Descriptor() ([]byte, []int) { - return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{3} + return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{5} } func (x *SlideDeck) GetConversionId() string { @@ -501,13 +709,14 @@ type CreateConversionRequest struct { SourceFilename string `protobuf:"bytes,1,opt,name=source_filename,json=sourceFilename,proto3" json:"source_filename,omitempty"` Full *SlideRasterOptions `protobuf:"bytes,2,opt,name=full,proto3" json:"full,omitempty"` Thumbnail *SlideRasterOptions `protobuf:"bytes,3,opt,name=thumbnail,proto3" json:"thumbnail,omitempty"` + Notes *NotesOptions `protobuf:"bytes,4,opt,name=notes,proto3" json:"notes,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *CreateConversionRequest) Reset() { *x = CreateConversionRequest{} - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[4] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -519,7 +728,7 @@ func (x *CreateConversionRequest) String() string { func (*CreateConversionRequest) ProtoMessage() {} func (x *CreateConversionRequest) ProtoReflect() protoreflect.Message { - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[4] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -532,7 +741,7 @@ func (x *CreateConversionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateConversionRequest.ProtoReflect.Descriptor instead. func (*CreateConversionRequest) Descriptor() ([]byte, []int) { - return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{4} + return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{6} } func (x *CreateConversionRequest) GetSourceFilename() string { @@ -556,6 +765,13 @@ func (x *CreateConversionRequest) GetThumbnail() *SlideRasterOptions { return nil } +func (x *CreateConversionRequest) GetNotes() *NotesOptions { + if x != nil { + return x.Notes + } + return nil +} + // CreateConversionResponse returns upload details for the session. type CreateConversionResponse struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -571,7 +787,7 @@ type CreateConversionResponse struct { func (x *CreateConversionResponse) Reset() { *x = CreateConversionResponse{} - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[5] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -583,7 +799,7 @@ func (x *CreateConversionResponse) String() string { func (*CreateConversionResponse) ProtoMessage() {} func (x *CreateConversionResponse) ProtoReflect() protoreflect.Message { - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[5] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -596,7 +812,7 @@ func (x *CreateConversionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateConversionResponse.ProtoReflect.Descriptor instead. func (*CreateConversionResponse) Descriptor() ([]byte, []int) { - return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{5} + return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{7} } func (x *CreateConversionResponse) GetConversionId() string { @@ -645,7 +861,7 @@ type StartConversionRequest struct { func (x *StartConversionRequest) Reset() { *x = StartConversionRequest{} - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[6] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -657,7 +873,7 @@ func (x *StartConversionRequest) String() string { func (*StartConversionRequest) ProtoMessage() {} func (x *StartConversionRequest) ProtoReflect() protoreflect.Message { - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[6] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -670,7 +886,7 @@ func (x *StartConversionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StartConversionRequest.ProtoReflect.Descriptor instead. func (*StartConversionRequest) Descriptor() ([]byte, []int) { - return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{6} + return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{8} } func (x *StartConversionRequest) GetConversionId() string { @@ -692,7 +908,7 @@ type StartConversionResponse struct { func (x *StartConversionResponse) Reset() { *x = StartConversionResponse{} - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[7] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -704,7 +920,7 @@ func (x *StartConversionResponse) String() string { func (*StartConversionResponse) ProtoMessage() {} func (x *StartConversionResponse) ProtoReflect() protoreflect.Message { - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[7] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -717,7 +933,7 @@ func (x *StartConversionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StartConversionResponse.ProtoReflect.Descriptor instead. func (*StartConversionResponse) Descriptor() ([]byte, []int) { - return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{7} + return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{9} } func (x *StartConversionResponse) GetConversionId() string { @@ -745,7 +961,7 @@ type GetConversionStatusRequest struct { func (x *GetConversionStatusRequest) Reset() { *x = GetConversionStatusRequest{} - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[8] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -757,7 +973,7 @@ func (x *GetConversionStatusRequest) String() string { func (*GetConversionStatusRequest) ProtoMessage() {} func (x *GetConversionStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[8] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -770,7 +986,7 @@ func (x *GetConversionStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetConversionStatusRequest.ProtoReflect.Descriptor instead. func (*GetConversionStatusRequest) Descriptor() ([]byte, []int) { - return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{8} + return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{10} } func (x *GetConversionStatusRequest) GetConversionId() string { @@ -797,7 +1013,7 @@ type GetConversionStatusResponse struct { func (x *GetConversionStatusResponse) Reset() { *x = GetConversionStatusResponse{} - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[9] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -809,7 +1025,7 @@ func (x *GetConversionStatusResponse) String() string { func (*GetConversionStatusResponse) ProtoMessage() {} func (x *GetConversionStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[9] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -822,7 +1038,7 @@ func (x *GetConversionStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetConversionStatusResponse.ProtoReflect.Descriptor instead. func (*GetConversionStatusResponse) Descriptor() ([]byte, []int) { - return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{9} + return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{11} } func (x *GetConversionStatusResponse) GetConversionId() string { @@ -885,7 +1101,7 @@ type GetSlideDeckRequest struct { func (x *GetSlideDeckRequest) Reset() { *x = GetSlideDeckRequest{} - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[10] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -897,7 +1113,7 @@ func (x *GetSlideDeckRequest) String() string { func (*GetSlideDeckRequest) ProtoMessage() {} func (x *GetSlideDeckRequest) ProtoReflect() protoreflect.Message { - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[10] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -910,7 +1126,7 @@ func (x *GetSlideDeckRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSlideDeckRequest.ProtoReflect.Descriptor instead. func (*GetSlideDeckRequest) Descriptor() ([]byte, []int) { - return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{10} + return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{12} } func (x *GetSlideDeckRequest) GetConversionId() string { @@ -930,7 +1146,7 @@ type GetSlideDeckResponse struct { func (x *GetSlideDeckResponse) Reset() { *x = GetSlideDeckResponse{} - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[11] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -942,7 +1158,7 @@ func (x *GetSlideDeckResponse) String() string { func (*GetSlideDeckResponse) ProtoMessage() {} func (x *GetSlideDeckResponse) ProtoReflect() protoreflect.Message { - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[11] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -955,7 +1171,7 @@ func (x *GetSlideDeckResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSlideDeckResponse.ProtoReflect.Descriptor instead. func (*GetSlideDeckResponse) Descriptor() ([]byte, []int) { - return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{11} + return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{13} } func (x *GetSlideDeckResponse) GetSlideDeck() *SlideDeck { @@ -976,7 +1192,7 @@ type DeleteConversionRequest struct { func (x *DeleteConversionRequest) Reset() { *x = DeleteConversionRequest{} - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[12] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -988,7 +1204,7 @@ func (x *DeleteConversionRequest) String() string { func (*DeleteConversionRequest) ProtoMessage() {} func (x *DeleteConversionRequest) ProtoReflect() protoreflect.Message { - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[12] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1001,7 +1217,7 @@ func (x *DeleteConversionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteConversionRequest.ProtoReflect.Descriptor instead. func (*DeleteConversionRequest) Descriptor() ([]byte, []int) { - return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{12} + return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{14} } func (x *DeleteConversionRequest) GetConversionId() string { @@ -1023,7 +1239,7 @@ type DeleteConversionResponse struct { func (x *DeleteConversionResponse) Reset() { *x = DeleteConversionResponse{} - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[13] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1035,7 +1251,7 @@ func (x *DeleteConversionResponse) String() string { func (*DeleteConversionResponse) ProtoMessage() {} func (x *DeleteConversionResponse) ProtoReflect() protoreflect.Message { - mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[13] + mi := &file_officeconvertapi_v1_conversion_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1048,7 +1264,7 @@ func (x *DeleteConversionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteConversionResponse.ProtoReflect.Descriptor instead. func (*DeleteConversionResponse) Descriptor() ([]byte, []int) { - return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{13} + return file_officeconvertapi_v1_conversion_proto_rawDescGZIP(), []int{15} } func (x *DeleteConversionResponse) GetConversionId() string { @@ -1077,13 +1293,29 @@ const file_officeconvertapi_v1_conversion_proto_rawDesc = "" + "resolution\x18\x01 \x01(\x0e2).officeconvertapi.v1.ConversionResolutionR\n" + "resolution\x12<\n" + "\x04jpeg\x18\x02 \x01(\v2&.officeconvertapi.v1.JpegOutputOptionsH\x00R\x04jpegB\b\n" + - "\x06format\"\x8b\x01\n" + + "\x06format\"\x87\x02\n" + + "\x14HtmlFormattingPolicy\x12\x1f\n" + + "\vignore_bold\x18\x01 \x01(\bR\n" + + "ignoreBold\x12#\n" + + "\rignore_italic\x18\x02 \x01(\bR\fignoreItalic\x12)\n" + + "\x10ignore_underline\x18\x03 \x01(\bR\x0fignoreUnderline\x121\n" + + "\x14ignore_strikethrough\x18\x04 \x01(\bR\x13ignoreStrikethrough\x12(\n" + + "\x10ignore_font_size\x18\x05 \x01(\bR\x0eignoreFontSize\x12!\n" + + "\fignore_color\x18\x06 \x01(\bR\vignoreColor\"\xec\x01\n" + + "\fNotesOptions\x128\n" + + "\x06format\x18\x01 \x01(\x0e2 .officeconvertapi.v1.NotesFormatR\x06format\x12:\n" + + "\x17html_use_paragraph_tags\x18\x02 \x01(\bH\x00R\x14htmlUseParagraphTags\x88\x01\x01\x12J\n" + + "\vhtml_policy\x18\x03 \x01(\v2).officeconvertapi.v1.HtmlFormattingPolicyR\n" + + "htmlPolicyB\x1a\n" + + "\x18_html_use_paragraph_tags\"\xaa\x01\n" + "\x05Slide\x12\x14\n" + "\x05index\x18\x01 \x01(\x05R\x05index\x12\x1f\n" + "\vnotes_plain\x18\x02 \x01(\tR\n" + "notesPlain\x12\x1b\n" + "\timage_url\x18\x03 \x01(\tR\bimageUrl\x12.\n" + - "\x13thumbnail_image_url\x18\x04 \x01(\tR\x11thumbnailImageUrl\"\xca\x02\n" + + "\x13thumbnail_image_url\x18\x04 \x01(\tR\x11thumbnailImageUrl\x12\x1d\n" + + "\n" + + "notes_html\x18\x05 \x01(\tR\tnotesHtml\"\xca\x02\n" + "\tSlideDeck\x12#\n" + "\rconversion_id\x18\x01 \x01(\tR\fconversionId\x12'\n" + "\x0fsource_filename\x18\x02 \x01(\tR\x0esourceFilename\x122\n" + @@ -1093,11 +1325,12 @@ const file_officeconvertapi_v1_conversion_proto_rawDesc = "" + "\x05width\x18\x05 \x01(\x05R\x05width\x12\x16\n" + "\x06height\x18\x06 \x01(\x05R\x06height\x12'\n" + "\x0fthumbnail_width\x18\a \x01(\x05R\x0ethumbnailWidth\x12)\n" + - "\x10thumbnail_height\x18\b \x01(\x05R\x0fthumbnailHeight\"\xc6\x01\n" + + "\x10thumbnail_height\x18\b \x01(\x05R\x0fthumbnailHeight\"\xff\x01\n" + "\x17CreateConversionRequest\x12'\n" + "\x0fsource_filename\x18\x01 \x01(\tR\x0esourceFilename\x12;\n" + "\x04full\x18\x02 \x01(\v2'.officeconvertapi.v1.SlideRasterOptionsR\x04full\x12E\n" + - "\tthumbnail\x18\x03 \x01(\v2'.officeconvertapi.v1.SlideRasterOptionsR\tthumbnail\"\xea\x01\n" + + "\tthumbnail\x18\x03 \x01(\v2'.officeconvertapi.v1.SlideRasterOptionsR\tthumbnail\x127\n" + + "\x05notes\x18\x04 \x01(\v2!.officeconvertapi.v1.NotesOptionsR\x05notes\"\xea\x01\n" + "\x18CreateConversionResponse\x12#\n" + "\rconversion_id\x18\x01 \x01(\tR\fconversionId\x12#\n" + "\rupload_bucket\x18\x02 \x01(\tR\fuploadBucket\x12*\n" + @@ -1151,7 +1384,11 @@ const file_officeconvertapi_v1_conversion_proto_rawDesc = "" + "\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" + + "\x19CONVERSION_RESOLUTION_UHD\x10\x05*Z\n" + + "\vNotesFormat\x12\x1c\n" + + "\x18NOTES_FORMAT_UNSPECIFIED\x10\x00\x12\x16\n" + + "\x12NOTES_FORMAT_PLAIN\x10\x01\x12\x15\n" + + "\x11NOTES_FORMAT_HTML\x10\x022\xcc\x04\n" + "\x11ConversionService\x12q\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" + @@ -1171,56 +1408,62 @@ func file_officeconvertapi_v1_conversion_proto_rawDescGZIP() []byte { return file_officeconvertapi_v1_conversion_proto_rawDescData } -var file_officeconvertapi_v1_conversion_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_officeconvertapi_v1_conversion_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_officeconvertapi_v1_conversion_proto_enumTypes = make([]protoimpl.EnumInfo, 4) +var file_officeconvertapi_v1_conversion_proto_msgTypes = make([]protoimpl.MessageInfo, 16) var file_officeconvertapi_v1_conversion_proto_goTypes = []any{ (ConversionStatus)(0), // 0: officeconvertapi.v1.ConversionStatus (ConversionPhase)(0), // 1: officeconvertapi.v1.ConversionPhase (ConversionResolution)(0), // 2: officeconvertapi.v1.ConversionResolution - (*JpegOutputOptions)(nil), // 3: officeconvertapi.v1.JpegOutputOptions - (*SlideRasterOptions)(nil), // 4: officeconvertapi.v1.SlideRasterOptions - (*Slide)(nil), // 5: officeconvertapi.v1.Slide - (*SlideDeck)(nil), // 6: officeconvertapi.v1.SlideDeck - (*CreateConversionRequest)(nil), // 7: officeconvertapi.v1.CreateConversionRequest - (*CreateConversionResponse)(nil), // 8: officeconvertapi.v1.CreateConversionResponse - (*StartConversionRequest)(nil), // 9: officeconvertapi.v1.StartConversionRequest - (*StartConversionResponse)(nil), // 10: officeconvertapi.v1.StartConversionResponse - (*GetConversionStatusRequest)(nil), // 11: officeconvertapi.v1.GetConversionStatusRequest - (*GetConversionStatusResponse)(nil), // 12: officeconvertapi.v1.GetConversionStatusResponse - (*GetSlideDeckRequest)(nil), // 13: officeconvertapi.v1.GetSlideDeckRequest - (*GetSlideDeckResponse)(nil), // 14: officeconvertapi.v1.GetSlideDeckResponse - (*DeleteConversionRequest)(nil), // 15: officeconvertapi.v1.DeleteConversionRequest - (*DeleteConversionResponse)(nil), // 16: officeconvertapi.v1.DeleteConversionResponse - (*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp + (NotesFormat)(0), // 3: officeconvertapi.v1.NotesFormat + (*JpegOutputOptions)(nil), // 4: officeconvertapi.v1.JpegOutputOptions + (*SlideRasterOptions)(nil), // 5: officeconvertapi.v1.SlideRasterOptions + (*HtmlFormattingPolicy)(nil), // 6: officeconvertapi.v1.HtmlFormattingPolicy + (*NotesOptions)(nil), // 7: officeconvertapi.v1.NotesOptions + (*Slide)(nil), // 8: officeconvertapi.v1.Slide + (*SlideDeck)(nil), // 9: officeconvertapi.v1.SlideDeck + (*CreateConversionRequest)(nil), // 10: officeconvertapi.v1.CreateConversionRequest + (*CreateConversionResponse)(nil), // 11: officeconvertapi.v1.CreateConversionResponse + (*StartConversionRequest)(nil), // 12: officeconvertapi.v1.StartConversionRequest + (*StartConversionResponse)(nil), // 13: officeconvertapi.v1.StartConversionResponse + (*GetConversionStatusRequest)(nil), // 14: officeconvertapi.v1.GetConversionStatusRequest + (*GetConversionStatusResponse)(nil), // 15: officeconvertapi.v1.GetConversionStatusResponse + (*GetSlideDeckRequest)(nil), // 16: officeconvertapi.v1.GetSlideDeckRequest + (*GetSlideDeckResponse)(nil), // 17: officeconvertapi.v1.GetSlideDeckResponse + (*DeleteConversionRequest)(nil), // 18: officeconvertapi.v1.DeleteConversionRequest + (*DeleteConversionResponse)(nil), // 19: officeconvertapi.v1.DeleteConversionResponse + (*timestamppb.Timestamp)(nil), // 20: google.protobuf.Timestamp } var file_officeconvertapi_v1_conversion_proto_depIdxs = []int32{ 2, // 0: officeconvertapi.v1.SlideRasterOptions.resolution:type_name -> officeconvertapi.v1.ConversionResolution - 3, // 1: officeconvertapi.v1.SlideRasterOptions.jpeg:type_name -> officeconvertapi.v1.JpegOutputOptions - 5, // 2: officeconvertapi.v1.SlideDeck.slides:type_name -> officeconvertapi.v1.Slide - 17, // 3: officeconvertapi.v1.SlideDeck.created_at:type_name -> google.protobuf.Timestamp - 4, // 4: officeconvertapi.v1.CreateConversionRequest.full:type_name -> officeconvertapi.v1.SlideRasterOptions - 4, // 5: officeconvertapi.v1.CreateConversionRequest.thumbnail:type_name -> officeconvertapi.v1.SlideRasterOptions - 17, // 6: officeconvertapi.v1.CreateConversionResponse.expires_at:type_name -> google.protobuf.Timestamp - 0, // 7: officeconvertapi.v1.StartConversionResponse.status:type_name -> officeconvertapi.v1.ConversionStatus - 0, // 8: officeconvertapi.v1.GetConversionStatusResponse.status:type_name -> officeconvertapi.v1.ConversionStatus - 17, // 9: officeconvertapi.v1.GetConversionStatusResponse.updated_at:type_name -> google.protobuf.Timestamp - 1, // 10: officeconvertapi.v1.GetConversionStatusResponse.phase:type_name -> officeconvertapi.v1.ConversionPhase - 6, // 11: officeconvertapi.v1.GetSlideDeckResponse.slide_deck:type_name -> officeconvertapi.v1.SlideDeck - 7, // 12: officeconvertapi.v1.ConversionService.CreateConversion:input_type -> officeconvertapi.v1.CreateConversionRequest - 9, // 13: officeconvertapi.v1.ConversionService.StartConversion:input_type -> officeconvertapi.v1.StartConversionRequest - 11, // 14: officeconvertapi.v1.ConversionService.GetConversionStatus:input_type -> officeconvertapi.v1.GetConversionStatusRequest - 13, // 15: officeconvertapi.v1.ConversionService.GetSlideDeck:input_type -> officeconvertapi.v1.GetSlideDeckRequest - 15, // 16: officeconvertapi.v1.ConversionService.DeleteConversion:input_type -> officeconvertapi.v1.DeleteConversionRequest - 8, // 17: officeconvertapi.v1.ConversionService.CreateConversion:output_type -> officeconvertapi.v1.CreateConversionResponse - 10, // 18: officeconvertapi.v1.ConversionService.StartConversion:output_type -> officeconvertapi.v1.StartConversionResponse - 12, // 19: officeconvertapi.v1.ConversionService.GetConversionStatus:output_type -> officeconvertapi.v1.GetConversionStatusResponse - 14, // 20: officeconvertapi.v1.ConversionService.GetSlideDeck:output_type -> officeconvertapi.v1.GetSlideDeckResponse - 16, // 21: officeconvertapi.v1.ConversionService.DeleteConversion:output_type -> officeconvertapi.v1.DeleteConversionResponse - 17, // [17:22] is the sub-list for method output_type - 12, // [12:17] is the sub-list for method input_type - 12, // [12:12] is the sub-list for extension type_name - 12, // [12:12] is the sub-list for extension extendee - 0, // [0:12] is the sub-list for field type_name + 4, // 1: officeconvertapi.v1.SlideRasterOptions.jpeg:type_name -> officeconvertapi.v1.JpegOutputOptions + 3, // 2: officeconvertapi.v1.NotesOptions.format:type_name -> officeconvertapi.v1.NotesFormat + 6, // 3: officeconvertapi.v1.NotesOptions.html_policy:type_name -> officeconvertapi.v1.HtmlFormattingPolicy + 8, // 4: officeconvertapi.v1.SlideDeck.slides:type_name -> officeconvertapi.v1.Slide + 20, // 5: officeconvertapi.v1.SlideDeck.created_at:type_name -> google.protobuf.Timestamp + 5, // 6: officeconvertapi.v1.CreateConversionRequest.full:type_name -> officeconvertapi.v1.SlideRasterOptions + 5, // 7: officeconvertapi.v1.CreateConversionRequest.thumbnail:type_name -> officeconvertapi.v1.SlideRasterOptions + 7, // 8: officeconvertapi.v1.CreateConversionRequest.notes:type_name -> officeconvertapi.v1.NotesOptions + 20, // 9: officeconvertapi.v1.CreateConversionResponse.expires_at:type_name -> google.protobuf.Timestamp + 0, // 10: officeconvertapi.v1.StartConversionResponse.status:type_name -> officeconvertapi.v1.ConversionStatus + 0, // 11: officeconvertapi.v1.GetConversionStatusResponse.status:type_name -> officeconvertapi.v1.ConversionStatus + 20, // 12: officeconvertapi.v1.GetConversionStatusResponse.updated_at:type_name -> google.protobuf.Timestamp + 1, // 13: officeconvertapi.v1.GetConversionStatusResponse.phase:type_name -> officeconvertapi.v1.ConversionPhase + 9, // 14: officeconvertapi.v1.GetSlideDeckResponse.slide_deck:type_name -> officeconvertapi.v1.SlideDeck + 10, // 15: officeconvertapi.v1.ConversionService.CreateConversion:input_type -> officeconvertapi.v1.CreateConversionRequest + 12, // 16: officeconvertapi.v1.ConversionService.StartConversion:input_type -> officeconvertapi.v1.StartConversionRequest + 14, // 17: officeconvertapi.v1.ConversionService.GetConversionStatus:input_type -> officeconvertapi.v1.GetConversionStatusRequest + 16, // 18: officeconvertapi.v1.ConversionService.GetSlideDeck:input_type -> officeconvertapi.v1.GetSlideDeckRequest + 18, // 19: officeconvertapi.v1.ConversionService.DeleteConversion:input_type -> officeconvertapi.v1.DeleteConversionRequest + 11, // 20: officeconvertapi.v1.ConversionService.CreateConversion:output_type -> officeconvertapi.v1.CreateConversionResponse + 13, // 21: officeconvertapi.v1.ConversionService.StartConversion:output_type -> officeconvertapi.v1.StartConversionResponse + 15, // 22: officeconvertapi.v1.ConversionService.GetConversionStatus:output_type -> officeconvertapi.v1.GetConversionStatusResponse + 17, // 23: officeconvertapi.v1.ConversionService.GetSlideDeck:output_type -> officeconvertapi.v1.GetSlideDeckResponse + 19, // 24: officeconvertapi.v1.ConversionService.DeleteConversion:output_type -> officeconvertapi.v1.DeleteConversionResponse + 20, // [20:25] is the sub-list for method output_type + 15, // [15:20] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name } func init() { file_officeconvertapi_v1_conversion_proto_init() } @@ -1231,13 +1474,14 @@ func file_officeconvertapi_v1_conversion_proto_init() { file_officeconvertapi_v1_conversion_proto_msgTypes[1].OneofWrappers = []any{ (*SlideRasterOptions_Jpeg)(nil), } + file_officeconvertapi_v1_conversion_proto_msgTypes[3].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_officeconvertapi_v1_conversion_proto_rawDesc), len(file_officeconvertapi_v1_conversion_proto_rawDesc)), - NumEnums: 3, - NumMessages: 14, + NumEnums: 4, + NumMessages: 16, NumExtensions: 0, NumServices: 1, }, diff --git a/gen/python/officeconvertapi/v1/conversion_connect.py b/gen/python/officeconvertapi/v1/conversion_connect.py index e36144f..bfec754 100644 --- a/gen/python/officeconvertapi/v1/conversion_connect.py +++ b/gen/python/officeconvertapi/v1/conversion_connect.py @@ -7,6 +7,7 @@ from typing import Protocol from connectrpc.client import ConnectClient, ConnectClientSync from connectrpc.code import Code +from connectrpc.codec import Codec from connectrpc.compression import Compression from connectrpc.errors import ConnectError from connectrpc.interceptor import Interceptor, InterceptorSync @@ -34,7 +35,7 @@ class ConversionService(Protocol): class ConversionServiceASGIApplication(ConnectASGIApplication[ConversionService]): - def __init__(self, service: ConversionService | AsyncGenerator[ConversionService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None: + def __init__(self, service: ConversionService | AsyncGenerator[ConversionService], *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None, codecs: Iterable[Codec] | None = None) -> None: super().__init__( service=service, endpoints=lambda svc: { @@ -92,6 +93,7 @@ class ConversionServiceASGIApplication(ConnectASGIApplication[ConversionService] interceptors=interceptors, read_max_bytes=read_max_bytes, compressions=compressions, + codecs=codecs, ) @property @@ -202,6 +204,9 @@ class ConversionServiceClient(ConnectClient): ) + + + class ConversionServiceSync(Protocol): def create_conversion(self, request: officeconvertapi_dot_v1_dot_conversion__pb2.CreateConversionRequest, ctx: RequestContext) -> officeconvertapi_dot_v1_dot_conversion__pb2.CreateConversionResponse: raise ConnectError(Code.UNIMPLEMENTED, "Not implemented") @@ -216,7 +221,7 @@ class ConversionServiceSync(Protocol): class ConversionServiceWSGIApplication(ConnectWSGIApplication): - def __init__(self, service: ConversionServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None) -> None: + def __init__(self, service: ConversionServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None, compressions: Iterable[Compression] | None = None, codecs: Iterable[Codec] | None = None) -> None: super().__init__( endpoints={ "/officeconvertapi.v1.ConversionService/CreateConversion": EndpointSync.unary( @@ -273,6 +278,7 @@ class ConversionServiceWSGIApplication(ConnectWSGIApplication): interceptors=interceptors, read_max_bytes=read_max_bytes, compressions=compressions, + codecs=codecs, ) @property @@ -381,3 +387,5 @@ class ConversionServiceClientSync(ConnectClientSync): headers=headers, timeout_ms=timeout_ms, ) + + diff --git a/gen/python/officeconvertapi/v1/conversion_pb2.py b/gen/python/officeconvertapi/v1/conversion_pb2.py index acb3237..b4dda39 100644 --- a/gen/python/officeconvertapi/v1/conversion_pb2.py +++ b/gen/python/officeconvertapi/v1/conversion_pb2.py @@ -25,7 +25,7 @@ _sym_db = _symbol_database.Default() 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\x11JpegOutputOptions\x12\x18\n\x07quality\x18\x01 \x01(\x05R\x07quality\"\xa7\x01\n\x12SlideRasterOptions\x12I\n\nresolution\x18\x01 \x01(\x0e\x32).officeconvertapi.v1.ConversionResolutionR\nresolution\x12<\n\x04jpeg\x18\x02 \x01(\x0b\x32&.officeconvertapi.v1.JpegOutputOptionsH\x00R\x04jpegB\x08\n\x06\x66ormat\"\x8b\x01\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\x12.\n\x13thumbnail_image_url\x18\x04 \x01(\tR\x11thumbnailImageUrl\"\xca\x02\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\x12\'\n\x0fthumbnail_width\x18\x07 \x01(\x05R\x0ethumbnailWidth\x12)\n\x10thumbnail_height\x18\x08 \x01(\x05R\x0fthumbnailHeight\"\xc6\x01\n\x17\x43reateConversionRequest\x12\'\n\x0fsource_filename\x18\x01 \x01(\tR\x0esourceFilename\x12;\n\x04\x66ull\x18\x02 \x01(\x0b\x32\'.officeconvertapi.v1.SlideRasterOptionsR\x04\x66ull\x12\x45\n\tthumbnail\x18\x03 \x01(\x0b\x32\'.officeconvertapi.v1.SlideRasterOptionsR\tthumbnail\"\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\x42ZZXgitea.auvem.com/end-internal/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\x11JpegOutputOptions\x12\x18\n\x07quality\x18\x01 \x01(\x05R\x07quality\"\xa7\x01\n\x12SlideRasterOptions\x12I\n\nresolution\x18\x01 \x01(\x0e\x32).officeconvertapi.v1.ConversionResolutionR\nresolution\x12<\n\x04jpeg\x18\x02 \x01(\x0b\x32&.officeconvertapi.v1.JpegOutputOptionsH\x00R\x04jpegB\x08\n\x06\x66ormat\"\x87\x02\n\x14HtmlFormattingPolicy\x12\x1f\n\x0bignore_bold\x18\x01 \x01(\x08R\nignoreBold\x12#\n\rignore_italic\x18\x02 \x01(\x08R\x0cignoreItalic\x12)\n\x10ignore_underline\x18\x03 \x01(\x08R\x0fignoreUnderline\x12\x31\n\x14ignore_strikethrough\x18\x04 \x01(\x08R\x13ignoreStrikethrough\x12(\n\x10ignore_font_size\x18\x05 \x01(\x08R\x0eignoreFontSize\x12!\n\x0cignore_color\x18\x06 \x01(\x08R\x0bignoreColor\"\xec\x01\n\x0cNotesOptions\x12\x38\n\x06\x66ormat\x18\x01 \x01(\x0e\x32 .officeconvertapi.v1.NotesFormatR\x06\x66ormat\x12:\n\x17html_use_paragraph_tags\x18\x02 \x01(\x08H\x00R\x14htmlUseParagraphTags\x88\x01\x01\x12J\n\x0bhtml_policy\x18\x03 \x01(\x0b\x32).officeconvertapi.v1.HtmlFormattingPolicyR\nhtmlPolicyB\x1a\n\x18_html_use_paragraph_tags\"\xaa\x01\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\x12.\n\x13thumbnail_image_url\x18\x04 \x01(\tR\x11thumbnailImageUrl\x12\x1d\n\nnotes_html\x18\x05 \x01(\tR\tnotesHtml\"\xca\x02\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\x12\'\n\x0fthumbnail_width\x18\x07 \x01(\x05R\x0ethumbnailWidth\x12)\n\x10thumbnail_height\x18\x08 \x01(\x05R\x0fthumbnailHeight\"\xff\x01\n\x17\x43reateConversionRequest\x12\'\n\x0fsource_filename\x18\x01 \x01(\tR\x0esourceFilename\x12;\n\x04\x66ull\x18\x02 \x01(\x0b\x32\'.officeconvertapi.v1.SlideRasterOptionsR\x04\x66ull\x12\x45\n\tthumbnail\x18\x03 \x01(\x0b\x32\'.officeconvertapi.v1.SlideRasterOptionsR\tthumbnail\x12\x37\n\x05notes\x18\x04 \x01(\x0b\x32!.officeconvertapi.v1.NotesOptionsR\x05notes\"\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*Z\n\x0bNotesFormat\x12\x1c\n\x18NOTES_FORMAT_UNSPECIFIED\x10\x00\x12\x16\n\x12NOTES_FORMAT_PLAIN\x10\x01\x12\x15\n\x11NOTES_FORMAT_HTML\x10\x02\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\x42ZZXgitea.auvem.com/end-internal/officeconvert/gen/go/officeconvertapi/v1;officeconvertapiv1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -33,40 +33,46 @@ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'officeconvertapi.v1.convers if not _descriptor._USE_C_DESCRIPTORS: _globals['DESCRIPTOR']._loaded_options = None _globals['DESCRIPTOR']._serialized_options = b'ZXgitea.auvem.com/end-internal/officeconvert/gen/go/officeconvertapi/v1;officeconvertapiv1' - _globals['_CONVERSIONSTATUS']._serialized_start=2150 - _globals['_CONVERSIONSTATUS']._serialized_end=2328 - _globals['_CONVERSIONPHASE']._serialized_start=2331 - _globals['_CONVERSIONPHASE']._serialized_end=2562 - _globals['_CONVERSIONRESOLUTION']._serialized_start=2565 - _globals['_CONVERSIONRESOLUTION']._serialized_end=2779 + _globals['_CONVERSIONSTATUS']._serialized_start=2743 + _globals['_CONVERSIONSTATUS']._serialized_end=2921 + _globals['_CONVERSIONPHASE']._serialized_start=2924 + _globals['_CONVERSIONPHASE']._serialized_end=3155 + _globals['_CONVERSIONRESOLUTION']._serialized_start=3158 + _globals['_CONVERSIONRESOLUTION']._serialized_end=3372 + _globals['_NOTESFORMAT']._serialized_start=3374 + _globals['_NOTESFORMAT']._serialized_end=3464 _globals['_JPEGOUTPUTOPTIONS']._serialized_start=94 _globals['_JPEGOUTPUTOPTIONS']._serialized_end=139 _globals['_SLIDERASTEROPTIONS']._serialized_start=142 _globals['_SLIDERASTEROPTIONS']._serialized_end=309 - _globals['_SLIDE']._serialized_start=312 - _globals['_SLIDE']._serialized_end=451 - _globals['_SLIDEDECK']._serialized_start=454 - _globals['_SLIDEDECK']._serialized_end=784 - _globals['_CREATECONVERSIONREQUEST']._serialized_start=787 - _globals['_CREATECONVERSIONREQUEST']._serialized_end=985 - _globals['_CREATECONVERSIONRESPONSE']._serialized_start=988 - _globals['_CREATECONVERSIONRESPONSE']._serialized_end=1222 - _globals['_STARTCONVERSIONREQUEST']._serialized_start=1224 - _globals['_STARTCONVERSIONREQUEST']._serialized_end=1285 - _globals['_STARTCONVERSIONRESPONSE']._serialized_start=1287 - _globals['_STARTCONVERSIONRESPONSE']._serialized_end=1412 - _globals['_GETCONVERSIONSTATUSREQUEST']._serialized_start=1414 - _globals['_GETCONVERSIONSTATUSREQUEST']._serialized_end=1479 - _globals['_GETCONVERSIONSTATUSRESPONSE']._serialized_start=1482 - _globals['_GETCONVERSIONSTATUSRESPONSE']._serialized_end=1845 - _globals['_GETSLIDEDECKREQUEST']._serialized_start=1847 - _globals['_GETSLIDEDECKREQUEST']._serialized_end=1905 - _globals['_GETSLIDEDECKRESPONSE']._serialized_start=1907 - _globals['_GETSLIDEDECKRESPONSE']._serialized_end=1992 - _globals['_DELETECONVERSIONREQUEST']._serialized_start=1994 - _globals['_DELETECONVERSIONREQUEST']._serialized_end=2056 - _globals['_DELETECONVERSIONRESPONSE']._serialized_start=2058 - _globals['_DELETECONVERSIONRESPONSE']._serialized_end=2147 - _globals['_CONVERSIONSERVICE']._serialized_start=2782 - _globals['_CONVERSIONSERVICE']._serialized_end=3370 + _globals['_HTMLFORMATTINGPOLICY']._serialized_start=312 + _globals['_HTMLFORMATTINGPOLICY']._serialized_end=575 + _globals['_NOTESOPTIONS']._serialized_start=578 + _globals['_NOTESOPTIONS']._serialized_end=814 + _globals['_SLIDE']._serialized_start=817 + _globals['_SLIDE']._serialized_end=987 + _globals['_SLIDEDECK']._serialized_start=990 + _globals['_SLIDEDECK']._serialized_end=1320 + _globals['_CREATECONVERSIONREQUEST']._serialized_start=1323 + _globals['_CREATECONVERSIONREQUEST']._serialized_end=1578 + _globals['_CREATECONVERSIONRESPONSE']._serialized_start=1581 + _globals['_CREATECONVERSIONRESPONSE']._serialized_end=1815 + _globals['_STARTCONVERSIONREQUEST']._serialized_start=1817 + _globals['_STARTCONVERSIONREQUEST']._serialized_end=1878 + _globals['_STARTCONVERSIONRESPONSE']._serialized_start=1880 + _globals['_STARTCONVERSIONRESPONSE']._serialized_end=2005 + _globals['_GETCONVERSIONSTATUSREQUEST']._serialized_start=2007 + _globals['_GETCONVERSIONSTATUSREQUEST']._serialized_end=2072 + _globals['_GETCONVERSIONSTATUSRESPONSE']._serialized_start=2075 + _globals['_GETCONVERSIONSTATUSRESPONSE']._serialized_end=2438 + _globals['_GETSLIDEDECKREQUEST']._serialized_start=2440 + _globals['_GETSLIDEDECKREQUEST']._serialized_end=2498 + _globals['_GETSLIDEDECKRESPONSE']._serialized_start=2500 + _globals['_GETSLIDEDECKRESPONSE']._serialized_end=2585 + _globals['_DELETECONVERSIONREQUEST']._serialized_start=2587 + _globals['_DELETECONVERSIONREQUEST']._serialized_end=2649 + _globals['_DELETECONVERSIONRESPONSE']._serialized_start=2651 + _globals['_DELETECONVERSIONRESPONSE']._serialized_end=2740 + _globals['_CONVERSIONSERVICE']._serialized_start=3467 + _globals['_CONVERSIONSERVICE']._serialized_end=4055 # @@protoc_insertion_point(module_scope) diff --git a/gen/python/officeconvertapi/v1/conversion_pb2.pyi b/gen/python/officeconvertapi/v1/conversion_pb2.pyi index 645c468..bda4a28 100644 --- a/gen/python/officeconvertapi/v1/conversion_pb2.pyi +++ b/gen/python/officeconvertapi/v1/conversion_pb2.pyi @@ -35,6 +35,12 @@ class ConversionResolution(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): CONVERSION_RESOLUTION_FHD: _ClassVar[ConversionResolution] CONVERSION_RESOLUTION_QHD: _ClassVar[ConversionResolution] CONVERSION_RESOLUTION_UHD: _ClassVar[ConversionResolution] + +class NotesFormat(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): + __slots__ = () + NOTES_FORMAT_UNSPECIFIED: _ClassVar[NotesFormat] + NOTES_FORMAT_PLAIN: _ClassVar[NotesFormat] + NOTES_FORMAT_HTML: _ClassVar[NotesFormat] CONVERSION_STATUS_UNSPECIFIED: ConversionStatus CONVERSION_STATUS_PENDING: ConversionStatus CONVERSION_STATUS_RUNNING: ConversionStatus @@ -52,6 +58,9 @@ CONVERSION_RESOLUTION_HD: ConversionResolution CONVERSION_RESOLUTION_FHD: ConversionResolution CONVERSION_RESOLUTION_QHD: ConversionResolution CONVERSION_RESOLUTION_UHD: ConversionResolution +NOTES_FORMAT_UNSPECIFIED: NotesFormat +NOTES_FORMAT_PLAIN: NotesFormat +NOTES_FORMAT_HTML: NotesFormat class JpegOutputOptions(_message.Message): __slots__ = ("quality",) @@ -67,17 +76,45 @@ class SlideRasterOptions(_message.Message): jpeg: JpegOutputOptions def __init__(self, resolution: _Optional[_Union[ConversionResolution, str]] = ..., jpeg: _Optional[_Union[JpegOutputOptions, _Mapping]] = ...) -> None: ... +class HtmlFormattingPolicy(_message.Message): + __slots__ = ("ignore_bold", "ignore_italic", "ignore_underline", "ignore_strikethrough", "ignore_font_size", "ignore_color") + IGNORE_BOLD_FIELD_NUMBER: _ClassVar[int] + IGNORE_ITALIC_FIELD_NUMBER: _ClassVar[int] + IGNORE_UNDERLINE_FIELD_NUMBER: _ClassVar[int] + IGNORE_STRIKETHROUGH_FIELD_NUMBER: _ClassVar[int] + IGNORE_FONT_SIZE_FIELD_NUMBER: _ClassVar[int] + IGNORE_COLOR_FIELD_NUMBER: _ClassVar[int] + ignore_bold: bool + ignore_italic: bool + ignore_underline: bool + ignore_strikethrough: bool + ignore_font_size: bool + ignore_color: bool + def __init__(self, ignore_bold: _Optional[bool] = ..., ignore_italic: _Optional[bool] = ..., ignore_underline: _Optional[bool] = ..., ignore_strikethrough: _Optional[bool] = ..., ignore_font_size: _Optional[bool] = ..., ignore_color: _Optional[bool] = ...) -> None: ... + +class NotesOptions(_message.Message): + __slots__ = ("format", "html_use_paragraph_tags", "html_policy") + FORMAT_FIELD_NUMBER: _ClassVar[int] + HTML_USE_PARAGRAPH_TAGS_FIELD_NUMBER: _ClassVar[int] + HTML_POLICY_FIELD_NUMBER: _ClassVar[int] + format: NotesFormat + html_use_paragraph_tags: bool + html_policy: HtmlFormattingPolicy + def __init__(self, format: _Optional[_Union[NotesFormat, str]] = ..., html_use_paragraph_tags: _Optional[bool] = ..., html_policy: _Optional[_Union[HtmlFormattingPolicy, _Mapping]] = ...) -> None: ... + class Slide(_message.Message): - __slots__ = ("index", "notes_plain", "image_url", "thumbnail_image_url") + __slots__ = ("index", "notes_plain", "image_url", "thumbnail_image_url", "notes_html") INDEX_FIELD_NUMBER: _ClassVar[int] NOTES_PLAIN_FIELD_NUMBER: _ClassVar[int] IMAGE_URL_FIELD_NUMBER: _ClassVar[int] THUMBNAIL_IMAGE_URL_FIELD_NUMBER: _ClassVar[int] + NOTES_HTML_FIELD_NUMBER: _ClassVar[int] index: int notes_plain: str image_url: str thumbnail_image_url: str - def __init__(self, index: _Optional[int] = ..., notes_plain: _Optional[str] = ..., image_url: _Optional[str] = ..., thumbnail_image_url: _Optional[str] = ...) -> None: ... + notes_html: str + def __init__(self, index: _Optional[int] = ..., notes_plain: _Optional[str] = ..., image_url: _Optional[str] = ..., thumbnail_image_url: _Optional[str] = ..., notes_html: _Optional[str] = ...) -> None: ... class SlideDeck(_message.Message): __slots__ = ("conversion_id", "source_filename", "slides", "created_at", "width", "height", "thumbnail_width", "thumbnail_height") @@ -100,14 +137,16 @@ class SlideDeck(_message.Message): 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] = ..., thumbnail_width: _Optional[int] = ..., thumbnail_height: _Optional[int] = ...) -> None: ... class CreateConversionRequest(_message.Message): - __slots__ = ("source_filename", "full", "thumbnail") + __slots__ = ("source_filename", "full", "thumbnail", "notes") SOURCE_FILENAME_FIELD_NUMBER: _ClassVar[int] FULL_FIELD_NUMBER: _ClassVar[int] THUMBNAIL_FIELD_NUMBER: _ClassVar[int] + NOTES_FIELD_NUMBER: _ClassVar[int] source_filename: str full: SlideRasterOptions thumbnail: SlideRasterOptions - def __init__(self, source_filename: _Optional[str] = ..., full: _Optional[_Union[SlideRasterOptions, _Mapping]] = ..., thumbnail: _Optional[_Union[SlideRasterOptions, _Mapping]] = ...) -> None: ... + notes: NotesOptions + def __init__(self, source_filename: _Optional[str] = ..., full: _Optional[_Union[SlideRasterOptions, _Mapping]] = ..., thumbnail: _Optional[_Union[SlideRasterOptions, _Mapping]] = ..., notes: _Optional[_Union[NotesOptions, _Mapping]] = ...) -> None: ... class CreateConversionResponse(_message.Message): __slots__ = ("conversion_id", "upload_bucket", "upload_object_key", "upload_url", "expires_at") diff --git a/proto/officeconvertapi/v1/conversion.proto b/proto/officeconvertapi/v1/conversion.proto index 717fbe3..a311e28 100644 --- a/proto/officeconvertapi/v1/conversion.proto +++ b/proto/officeconvertapi/v1/conversion.proto @@ -68,6 +68,33 @@ message SlideRasterOptions { } } +// NotesFormat controls what note representation the server should compute. +enum NotesFormat { + NOTES_FORMAT_UNSPECIFIED = 0; + NOTES_FORMAT_PLAIN = 1; + NOTES_FORMAT_HTML = 2; +} + +// HtmlFormattingPolicy configures which formatting features are ignored in HTML mode. +message HtmlFormattingPolicy { + bool ignore_bold = 1; + bool ignore_italic = 2; + bool ignore_underline = 3; + bool ignore_strikethrough = 4; + bool ignore_font_size = 5; + bool ignore_color = 6; +} + +// NotesOptions configures note extraction behavior. +message NotesOptions { + // Output format for extracted notes. + NotesFormat format = 1; + // If true, wrap PPTX paragraphs as

blocks in HTML mode. If false, emit
only. + optional bool html_use_paragraph_tags = 2; + // Formatting policy for HTML mode. + HtmlFormattingPolicy html_policy = 3; +} + // Slide contains extracted notes and the rendered image URL for one slide. message Slide { int32 index = 1; @@ -76,6 +103,8 @@ message Slide { string image_url = 3; // Thumbnail rendered image URL. string thumbnail_image_url = 4; + // Optional, sanitized HTML version of notes when requested. + string notes_html = 5; } // SlideDeck is the final structured conversion artifact. @@ -100,6 +129,7 @@ message CreateConversionRequest { string source_filename = 1; SlideRasterOptions full = 2; SlideRasterOptions thumbnail = 3; + NotesOptions notes = 4; } // CreateConversionResponse returns upload details for the session. diff --git a/python/packages/officeconvert/src/officeconvert/__init__.py b/python/packages/officeconvert/src/officeconvert/__init__.py index 8375318..e26a65a 100644 --- a/python/packages/officeconvert/src/officeconvert/__init__.py +++ b/python/packages/officeconvert/src/officeconvert/__init__.py @@ -1,19 +1,27 @@ """Public conversion APIs for the officeconvert Python library.""" from officeconvert.conversion import ( + HtmlFormattingPolicy, + NotesFormat, + NotesOptions, SlideArtifact, SlideDeckResult, convert_pptx_to_pdf, convert_pptx_to_slidedeck, extract_slide_notes, + extract_slide_notes_html, render_pdf_to_images, ) __all__ = [ + "HtmlFormattingPolicy", + "NotesFormat", + "NotesOptions", "SlideArtifact", "SlideDeckResult", "convert_pptx_to_pdf", "convert_pptx_to_slidedeck", "extract_slide_notes", + "extract_slide_notes_html", "render_pdf_to_images", ] diff --git a/python/packages/officeconvert/src/officeconvert/conversion.py b/python/packages/officeconvert/src/officeconvert/conversion.py index effcb60..13fb59f 100644 --- a/python/packages/officeconvert/src/officeconvert/conversion.py +++ b/python/packages/officeconvert/src/officeconvert/conversion.py @@ -4,6 +4,8 @@ from __future__ import annotations from collections.abc import Callable from dataclasses import dataclass +from enum import Enum +import html import logging import math from pathlib import Path @@ -13,6 +15,28 @@ from typing import Iterable from pptx import Presentation +class NotesFormat(str, Enum): + PLAIN = "plain" + HTML = "html" + + +@dataclass(frozen=True, slots=True) +class HtmlFormattingPolicy: + ignore_bold: bool = False + ignore_italic: bool = False + ignore_underline: bool = False + ignore_strikethrough: bool = False + ignore_font_size: bool = False + ignore_color: bool = False + + +@dataclass(frozen=True, slots=True) +class NotesOptions: + format: NotesFormat = NotesFormat.PLAIN + html_use_paragraph_tags: bool = True + html_policy: HtmlFormattingPolicy = HtmlFormattingPolicy() + + @dataclass(frozen=True, slots=True) class SlideArtifact: """Represents one converted slide image and its extracted notes.""" @@ -21,6 +45,7 @@ class SlideArtifact: image_path: Path thumbnail_path: Path notes_plain: str + notes_html: str = "" @dataclass(frozen=True, slots=True) @@ -290,14 +315,52 @@ def extract_slide_notes(pptx_path: Path) -> list[str]: if not pptx_path.exists(): raise FileNotFoundError(f"source PPTX does not exist: {pptx_path}") + plain, _html = _extract_slide_notes(pptx_path, options=NotesOptions(format=NotesFormat.PLAIN)) + return plain + + +def extract_slide_notes_html( + pptx_path: Path, + *, + options: NotesOptions | None = None, +) -> list[str]: + """Extract sanitized HTML notes for each slide in slide index order. + + The returned HTML is sanitized-by-construction: + - text content is always escaped + - only a small allowlist of tags is emitted: p, br, strong, em, u, s, span + - only `style` attributes generated by this function are emitted on span tags + """ + if not pptx_path.exists(): + raise FileNotFoundError(f"source PPTX does not exist: {pptx_path}") + resolved = options or NotesOptions(format=NotesFormat.HTML) + if resolved.format != NotesFormat.HTML: + raise ValueError("extract_slide_notes_html requires NotesOptions.format=NotesFormat.HTML") + + _plain, html_notes = _extract_slide_notes(pptx_path, options=resolved) + return html_notes + + +def _extract_slide_notes( + pptx_path: Path, + *, + options: NotesOptions, +) -> tuple[list[str], list[str]]: presentation = Presentation(str(pptx_path.resolve())) - notes: list[str] = [] + want_html = options.format == NotesFormat.HTML + + plain_notes: list[str] = [] + html_notes: list[str] = [] for slide in presentation.slides: if not slide.has_notes_slide: - notes.append("") + plain_notes.append("") + html_notes.append("") continue - notes.append(_extract_notes_text(slide.notes_slide.shapes)) - return notes + plain = _extract_notes_text(slide.notes_slide.shapes) + plain_notes.append(plain) + html_notes.append(_extract_notes_html(slide.notes_slide.shapes, options=options) if want_html else "") + + return plain_notes, html_notes def convert_pptx_to_slidedeck( @@ -314,6 +377,7 @@ def convert_pptx_to_slidedeck( pptx_to_pdf_per_slide_timeout_s: int = 3, pdf_to_images_base_timeout_s: int = 30, pdf_to_images_per_slide_timeout_s: int = 8, + notes_options: NotesOptions | None = None, progress_callback: ProgressCallback | None = None, ) -> SlideDeckResult: """Convert a PPTX into rendered images and extracted notes. @@ -344,8 +408,9 @@ def convert_pptx_to_slidedeck( full_image_dir = work_dir / "slides_full" thumbnail_image_dir = work_dir / "slides_thumb" + resolved_notes_options = notes_options or NotesOptions(format=NotesFormat.PLAIN) _emit_progress(progress_callback, PHASE_EXTRACTING_NOTES, 0, 1) - notes = extract_slide_notes(pptx_path) + notes_plain, notes_html = _extract_slide_notes(pptx_path, options=resolved_notes_options) _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( @@ -370,7 +435,7 @@ def convert_pptx_to_slidedeck( output_width_px=thumbnail_width, output_height_px=thumbnail_height, ) - slide_count = len(notes) + slide_count = len(notes_plain) pptx_to_pdf_timeout = _compute_adaptive_timeout( slide_count=slide_count, timeout_cap_s=pptx_to_pdf_timeout_s, @@ -454,15 +519,15 @@ def convert_pptx_to_slidedeck( ), ) - if len(full_image_paths) != len(notes): + if len(full_image_paths) != len(notes_plain): raise ValueError( "rendered full-size slide count does not match note count: " - f"{len(full_image_paths)} image(s) vs {len(notes)} note entries" + f"{len(full_image_paths)} image(s) vs {len(notes_plain)} note entries" ) - if len(thumbnail_image_paths) != len(notes): + if len(thumbnail_image_paths) != len(notes_plain): raise ValueError( "rendered thumbnail slide count does not match note count: " - f"{len(thumbnail_image_paths)} image(s) vs {len(notes)} note entries" + f"{len(thumbnail_image_paths)} image(s) vs {len(notes_plain)} note entries" ) slides = [ @@ -470,10 +535,11 @@ def convert_pptx_to_slidedeck( index=index, image_path=image_path, thumbnail_path=thumbnail_path, - notes_plain=note, + notes_plain=plain, + notes_html=html, ) - for index, (image_path, thumbnail_path, note) in enumerate( - zip(full_image_paths, thumbnail_image_paths, notes), + for index, (image_path, thumbnail_path, plain, html) in enumerate( + zip(full_image_paths, thumbnail_image_paths, notes_plain, notes_html), start=1, ) ] @@ -632,3 +698,102 @@ def _extract_notes_text(shapes: Iterable[object]) -> str: if text: segments.append(text) return "\n\n".join(segments).strip() + + +def _extract_notes_html(shapes: Iterable[object], *, options: NotesOptions) -> str: + """Extract sanitized HTML from note shapes while preserving paragraph boundaries.""" + paragraphs_html: list[str] = [] + for shape in shapes: + text_frame = getattr(shape, "text_frame", None) + if text_frame is None: + continue + for paragraph in getattr(text_frame, "paragraphs", []) or []: + paragraph_html = _paragraph_to_html(paragraph, options=options) + if paragraph_html: + paragraphs_html.append(paragraph_html) + + if not paragraphs_html: + return "" + if options.html_use_paragraph_tags: + return "".join(paragraphs_html) + # Flatten paragraph boundaries into
separators (double-break between paragraphs). + return "

".join( + p.removeprefix("

").removesuffix("

") if p.startswith("

") else p + for p in paragraphs_html + ) + + +def _paragraph_to_html(paragraph: object, *, options: NotesOptions) -> str: + policy = options.html_policy + + parts: list[str] = [] + for run in getattr(paragraph, "runs", []) or []: + text = getattr(run, "text", "") or "" + if not text: + continue + # Escape first, then re-introduce only allowlisted tags. + escaped = html.escape(text, quote=False) + escaped = escaped.replace("\n", "
") + + font = getattr(run, "font", None) + style = "" + if font is not None: + if not policy.ignore_color: + rgb_obj = getattr(getattr(font, "color", None), "rgb", None) + if rgb_obj is not None: + rgb = str(rgb_obj) + if isinstance(rgb, str) and len(rgb) == 6: + style += f"color: #{rgb};" + if not policy.ignore_font_size: + size = getattr(font, "size", None) + pt = getattr(size, "pt", None) + if isinstance(pt, (int, float)): + # Clamp to a sane range to avoid pathological CSS. + if 0.5 <= pt <= 512: + pt_str = str(int(pt)) if float(pt).is_integer() else str(round(float(pt), 2)) + style += f"font-size: {pt_str}pt;" + + content = escaped + if style: + content = f"{content}" + + if font is not None: + if not policy.ignore_bold and getattr(font, "bold", None) is True: + content = f"{content}" + if not policy.ignore_italic and getattr(font, "italic", None) is True: + content = f"{content}" + if not policy.ignore_underline and _truthy_underline(getattr(font, "underline", None)): + content = f"{content}" + if not policy.ignore_strikethrough and _truthy_strikethrough(run): + content = f"{content}" + + parts.append(content) + + inner = "".join(parts).strip() + if not inner: + return "" + if options.html_use_paragraph_tags: + return f"

{inner}

" + return inner + + +def _truthy_underline(value: object) -> bool: + # python-pptx may represent underline as True/False/None or an enum value. + if value is True: + return True + if value in (None, False): + return False + # Any non-falsey, non-None value implies underline style. + return True + + +def _truthy_strikethrough(run: object) -> bool: + # python-pptx doesn't currently expose a first-class Font.strike property; detect via XML. + xml_run = getattr(run, "_r", None) + rpr = getattr(xml_run, "rPr", None) + if rpr is None: + return False + strike_val = rpr.get("strike") + if strike_val in (None, "noStrike", "false", "0"): + return False + return True diff --git a/python/packages/officeconvert/tests/test_notes_html.py b/python/packages/officeconvert/tests/test_notes_html.py new file mode 100644 index 0000000..50d3f67 --- /dev/null +++ b/python/packages/officeconvert/tests/test_notes_html.py @@ -0,0 +1,111 @@ +import tempfile +import unittest +from pathlib import Path + +from pptx import Presentation +from pptx.dml.color import RGBColor +from pptx.util import Pt + +from officeconvert.conversion import HtmlFormattingPolicy, NotesFormat, NotesOptions, extract_slide_notes_html + + +def _build_pptx_with_formatted_notes(tmp_path: Path) -> Path: + prs = Presentation() + slide = prs.slides.add_slide(prs.slide_layouts[5]) # blank + + notes = slide.notes_slide + tf = notes.notes_text_frame + + # First paragraph: mixed runs with formatting. + p1 = tf.paragraphs[0] + p1.text = "" + r1 = p1.add_run() + r1.text = "BoldRed24 " + r1.font.bold = True + r1.font.color.rgb = RGBColor(0xFF, 0x00, 0x00) + r1.font.size = Pt(24) + + r2 = p1.add_run() + r2.text = "UnderStrike" + r2.font.underline = True + # python-pptx does not currently expose a first-class API for strikethrough, + # but the underlying DrawingML uses a:rPr@strike="sngStrike" or "dblStrike". + r2._r.rPr.set("strike", "sngStrike") + + # Second paragraph: ensure escaping is applied. + p2 = tf.add_paragraph() + r3 = p2.add_run() + r3.text = "" + r3.font.italic = True + + out = tmp_path / "notes.pptx" + prs.save(out) + return out + + +class NotesHtmlExtractionTests(unittest.TestCase): + def test_extracts_basic_rich_text_and_escapes(self) -> None: + with tempfile.TemporaryDirectory() as d: + pptx_path = _build_pptx_with_formatted_notes(Path(d)) + html_notes = extract_slide_notes_html( + pptx_path, + options=NotesOptions(format=NotesFormat.HTML, html_use_paragraph_tags=True), + ) + + self.assertEqual(len(html_notes), 1) + html_out = html_notes[0] + + # Paragraphs are wrapped in

. + self.assertIn("

", html_out) + self.assertIn("

", html_out) + + # Formatting tags. + self.assertIn("", html_out) + self.assertIn("", html_out) + self.assertIn("", html_out) + self.assertIn("", html_out) + + # Style tags for RGB and font size. + self.assertIn('style="color: #FF0000;font-size: 24pt;"', html_out) + + # Escaping: no raw