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) for i := range tableArr { tableArr[i] = make([]string, params.maxColumn) } 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: for _, id := range s.getChildIds(block) { s.addComponentTable(ctx, blockMap[id], blockMap, params) } case types.BlockTypeCell: 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) } if params.maxRow < int(*block.RowIndex) { params.maxRow = int(*block.RowIndex) } if params.maxColumn < int(*block.ColumnIndex) { params.maxColumn = int(*block.ColumnIndex) } params.table = append(params.table, cell{ column: int(*block.ColumnIndex) - 1, row: int(*block.RowIndex) - 1, value: str.String(), }) } default: slog.Info("unhandled block type in table", "type", block.BlockType) } } func (s *Service) getTables(ctx context.Context, document documenttypes.File, index int) ([]uuid.UUID, map[uuid.UUID]types.Block, error) { pageBytes, err := document.GetPageAsPNG(ctx, index) if err != nil { return nil, nil, err } res, err := s.cfg.GetTextractClient().AnalyzeDocument(ctx, &textract.AnalyzeDocumentInput{ Document: &types.Document{ Bytes: pageBytes, }, FeatureTypes: []types.FeatureType{ types.FeatureTypeTables, }, }) if err != nil { return nil, nil, 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", "error", err, "id", *block.Id) continue } tables = append(tables, id) } } blocks := s.getBlockMap(res.Blocks) return tables, blocks, nil }