418a2761b3
Merged Cell * mergecellv1 * buildimg * merging * addfile * justmergedcell
171 lines
4.1 KiB
Go
171 lines
4.1 KiB
Go
package documenttext
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"log/slog"
|
|
"strings"
|
|
|
|
documenttypes "queryorchestration/internal/document/types"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/service/textract"
|
|
"github.com/aws/aws-sdk-go-v2/service/textract/types"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type cell struct {
|
|
value string
|
|
row int
|
|
column int
|
|
}
|
|
|
|
func (s *Service) addTable(ctx context.Context, block types.Block, blockMap map[uuid.UUID]types.Block, builder *strings.Builder) error {
|
|
params := tableParams{
|
|
maxRow: 0,
|
|
maxColumn: 0,
|
|
table: []cell{},
|
|
}
|
|
|
|
directChildren := s.getDirectChildren(block, blockMap)
|
|
|
|
for _, uid := range directChildren {
|
|
s.addComponentTable(ctx, blockMap[uid], blockMap, ¶ms)
|
|
}
|
|
|
|
tableArr := make([][]string, params.maxRow+1)
|
|
for i := range tableArr {
|
|
tableArr[i] = make([]string, params.maxColumn+1)
|
|
}
|
|
|
|
for _, cell := range params.table {
|
|
tableArr[cell.row][cell.column] = cell.value
|
|
}
|
|
|
|
jsonData, err := json.Marshal(tableArr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
builder.WriteString("-------Table Start--------\n")
|
|
builder.WriteString(string(jsonData))
|
|
builder.WriteString("\n-------Table End--------\n")
|
|
|
|
return nil
|
|
}
|
|
|
|
type tableParams struct {
|
|
maxRow int
|
|
maxColumn int
|
|
table []cell
|
|
}
|
|
|
|
func (s *Service) addComponentTable(ctx context.Context, block types.Block, blockMap map[uuid.UUID]types.Block, params *tableParams) {
|
|
switch block.BlockType {
|
|
case types.BlockTypeMergedCell:
|
|
content := ""
|
|
for _, uid := range s.getChildIds(block) {
|
|
if blockMap[uid].BlockType != types.BlockTypeCell {
|
|
slog.Warn("not a cell", "block_type", blockMap[uid].BlockType)
|
|
continue
|
|
}
|
|
content = s.getCellContent(blockMap[uid], blockMap)
|
|
if content != "" {
|
|
break
|
|
}
|
|
}
|
|
startColumnIndex := int(*block.ColumnIndex - 1)
|
|
startRowIndex := int(*block.RowIndex - 1)
|
|
endColumnIndex := startColumnIndex + int(*block.ColumnSpan) - 1
|
|
endRowIndex := startRowIndex + int(*block.RowSpan) - 1
|
|
for row := startRowIndex; row <= endRowIndex; row++ {
|
|
for column := startColumnIndex; column <= endColumnIndex; column++ {
|
|
s.addCellToTable(
|
|
row,
|
|
column,
|
|
content,
|
|
params,
|
|
)
|
|
}
|
|
}
|
|
case types.BlockTypeCell:
|
|
content := s.getCellContent(block, blockMap)
|
|
s.addCellToTable(
|
|
int(*block.RowIndex)-1,
|
|
int(*block.ColumnIndex)-1,
|
|
content,
|
|
params,
|
|
)
|
|
default:
|
|
slog.Info("unhandled block type in table", "type", block.BlockType)
|
|
}
|
|
}
|
|
|
|
func (s *Service) getCellContent(block types.Block, blockMap map[uuid.UUID]types.Block) string {
|
|
var str strings.Builder
|
|
for _, uid := range s.getChildIds(block) {
|
|
if blockMap[uid].BlockType == types.BlockTypeWord {
|
|
if str.String() != "" {
|
|
str.WriteRune(' ')
|
|
}
|
|
str.WriteString(*blockMap[uid].Text)
|
|
}
|
|
}
|
|
|
|
return str.String()
|
|
}
|
|
|
|
func (s *Service) addCellToTable(rowIndex int, columnIndex int, content string, params *tableParams) {
|
|
if params.maxRow < rowIndex {
|
|
params.maxRow = rowIndex
|
|
}
|
|
if params.maxColumn < columnIndex {
|
|
params.maxColumn = columnIndex
|
|
}
|
|
params.table = append(params.table, cell{
|
|
column: columnIndex,
|
|
row: rowIndex,
|
|
value: content,
|
|
})
|
|
}
|
|
|
|
type specialisedFeatures struct {
|
|
BlockMap map[uuid.UUID]types.Block
|
|
Tables []uuid.UUID
|
|
}
|
|
|
|
func (s *Service) getSpecialisedFeatures(ctx context.Context, document documenttypes.File, index int, features []types.FeatureType) (specialisedFeatures, error) {
|
|
pageBytes, err := document.GetPageAsPNG(ctx, index)
|
|
if err != nil {
|
|
return specialisedFeatures{}, err
|
|
}
|
|
|
|
res, err := s.cfg.GetTextractClient().AnalyzeDocument(ctx, &textract.AnalyzeDocumentInput{
|
|
Document: &types.Document{
|
|
Bytes: pageBytes,
|
|
},
|
|
FeatureTypes: features,
|
|
})
|
|
if err != nil {
|
|
return specialisedFeatures{}, err
|
|
}
|
|
|
|
tables := []uuid.UUID{}
|
|
for _, block := range res.Blocks {
|
|
if block.BlockType == types.BlockTypeTable {
|
|
id, err := uuid.Parse(*block.Id)
|
|
if err != nil {
|
|
slog.Warn("error parsing block id for tables", "error", err, "id", *block.Id)
|
|
continue
|
|
}
|
|
|
|
tables = append(tables, id)
|
|
}
|
|
}
|
|
blocks := s.getBlockMap(res.Blocks)
|
|
|
|
return specialisedFeatures{
|
|
BlockMap: blocks,
|
|
Tables: tables,
|
|
}, nil
|
|
}
|