Files
query-orchestration/internal/document/text/tables.go
T
Michael McGuinness 418a2761b3 Merged in feature/mergecell (pull request #142)
Merged Cell

* mergecellv1

* buildimg

* merging

* addfile

* justmergedcell
2025-05-13 12:33:34 +00:00

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, &params)
}
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
}