pyflutter-app 0.2.4__tar.gz → 0.2.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/PKG-INFO +1 -1
  2. pyflutter_app-0.2.7/cartas/__init__.py +6 -0
  3. pyflutter_app-0.2.7/cartas/_table_toi.py +151 -0
  4. pyflutter_app-0.2.7/cartas/common.py +68 -0
  5. pyflutter_app-0.2.7/cartas/find_toi.py +27 -0
  6. pyflutter_app-0.2.7/cartas/relatorio.py +350 -0
  7. pyflutter_app-0.2.7/converter/__init__.py +1 -0
  8. pyflutter_app-0.2.7/converter/__main__.py +9 -0
  9. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/converter/home_page/_page_edit.py +1 -1
  10. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/converter/home_page/view.py +6 -7
  11. pyflutter_app-0.2.7/converter/page_forms/Diagnorstico.txt +108 -0
  12. pyflutter_app-0.2.7/converter/page_forms/__init__.py +5 -0
  13. pyflutter_app-0.2.7/converter/page_forms/common.py +177 -0
  14. pyflutter_app-0.2.7/converter/page_forms/config.py +68 -0
  15. pyflutter_app-0.2.7/converter/page_forms/controller_forms.py +234 -0
  16. pyflutter_app-0.2.7/converter/page_forms/diagnose_forms.py +64 -0
  17. pyflutter_app-0.2.7/converter/page_forms/model_forms.py +186 -0
  18. pyflutter_app-0.2.7/converter/page_forms/service.py +347 -0
  19. pyflutter_app-0.2.7/converter/page_forms/view_forms.py +104 -0
  20. pyflutter_app-0.2.4/converter/run.py → pyflutter_app-0.2.7/converter/run_app_convert.py +4 -8
  21. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/converter/util.py +6 -3
  22. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/export_app.sh +14 -10
  23. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/main.py +5 -5
  24. pyflutter_app-0.2.7/mediator.py +247 -0
  25. pyflutter_app-0.2.7/mvc/controller.py +60 -0
  26. pyflutter_app-0.2.7/mvc/model.py +40 -0
  27. pyflutter_app-0.2.7/mvc/view.py +133 -0
  28. pyflutter_app-0.2.7/new-export_app.sh +60 -0
  29. pyflutter_app-0.2.7/ocrlib/__init__.py +54 -0
  30. pyflutter_app-0.2.7/ocrlib/_common.py +282 -0
  31. pyflutter_app-0.2.4/ocrlib/pdf_convert.py → pyflutter_app-0.2.7/ocrlib/_pdf_convert.py +126 -87
  32. pyflutter_app-0.2.7/ocrlib/_table_ocr.py +578 -0
  33. pyflutter_app-0.2.7/ocrlib/_tesseract.py +356 -0
  34. pyflutter_app-0.2.7/ocrlib/erros.py +5 -0
  35. pyflutter_app-0.2.7/ocrlib/relatorio_ocr.py +578 -0
  36. pyflutter_app-0.2.7/ocrlib/util.py +29 -0
  37. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/pyflutter_ui/file_picker.py +8 -7
  38. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/pyflutter_ui/ui/core.py +1 -1
  39. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/pyproject.toml +11 -2
  40. pyflutter_app-0.2.7/pyproject.toml.back +35 -0
  41. pyflutter_app-0.2.7/table_stream/__init__.py +92 -0
  42. pyflutter_app-0.2.7/table_stream/erros.py +162 -0
  43. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/table_stream/hash_map.py +85 -24
  44. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/table_stream/notifier.py +5 -5
  45. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/table_stream/pattner/adapter.py +2 -3
  46. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/table_stream/sysfiles.py +221 -180
  47. pyflutter_app-0.2.7/table_stream/table.py +835 -0
  48. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/table_stream/thread.py +1 -0
  49. pyflutter_app-0.2.7/test.py +36 -0
  50. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/uv.lock +1 -1
  51. pyflutter_app-0.2.7/whatsapp_files/__init__.py +12 -0
  52. pyflutter_app-0.2.7/whatsapp_files/_table_whatsapp.py +461 -0
  53. pyflutter_app-0.2.7/whatsapp_files/common.py +120 -0
  54. pyflutter_app-0.2.7/whatsapp_files/erros.py +11 -0
  55. pyflutter_app-0.2.7/whatsapp_files/stream_files.py +390 -0
  56. pyflutter_app-0.2.4/converter/__init__.py +0 -1
  57. pyflutter_app-0.2.4/converter/__main__.py +0 -9
  58. pyflutter_app-0.2.4/converter/page_forms/__init__.py +0 -191
  59. pyflutter_app-0.2.4/converter/page_forms/common.py +0 -155
  60. pyflutter_app-0.2.4/converter/page_forms/config.py +0 -199
  61. pyflutter_app-0.2.4/converter/page_forms/controller_forms.py +0 -193
  62. pyflutter_app-0.2.4/converter/page_forms/model_forms.py +0 -68
  63. pyflutter_app-0.2.4/converter/page_forms/service.py +0 -207
  64. pyflutter_app-0.2.4/ocrlib/modules.py +0 -178
  65. pyflutter_app-0.2.4/ocrlib/recognize.py +0 -1034
  66. pyflutter_app-0.2.4/ocrlib/util.py +0 -6
  67. pyflutter_app-0.2.4/table_stream/__init__.py +0 -22
  68. pyflutter_app-0.2.4/table_stream/erros.py +0 -102
  69. pyflutter_app-0.2.4/test.py +0 -63
  70. pyflutter_app-0.2.4/whatsapp_files/file_names.py +0 -678
  71. pyflutter_app-0.2.4/whatsapp_files/stream_files.py +0 -417
  72. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/.gitignore +0 -0
  73. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/.idea/.gitignore +0 -0
  74. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/.idea/inspectionProfiles/Project_Default.xml +0 -0
  75. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
  76. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/.idea/misc.xml +0 -0
  77. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/.idea/modules.xml +0 -0
  78. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/.idea/pyflutter_app.iml +0 -0
  79. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/.idea/vcs.xml +0 -0
  80. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/README.md +0 -0
  81. pyflutter_app-0.2.4/converter/home_page/__init__.py → pyflutter_app-0.2.7/cartas/erros.py +0 -0
  82. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/converter/assets/forms_config.json +0 -0
  83. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/converter/config_app.py +0 -0
  84. {pyflutter_app-0.2.4/converter/whatsapp → pyflutter_app-0.2.7/converter/home_page}/__init__.py +0 -0
  85. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/converter/home_page/controller.py +0 -0
  86. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/converter/home_page/model.py +0 -0
  87. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/converter/lib_toi.py +0 -0
  88. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/converter/table_widget.py +0 -0
  89. {pyflutter_app-0.2.4/whatsapp_files → pyflutter_app-0.2.7/converter/whatsapp}/__init__.py +0 -0
  90. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/converter/whatsapp/model.py +0 -0
  91. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/local_build/linux.sh +0 -0
  92. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/local_build/send.sh +0 -0
  93. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/ocrlib/export_ocr.sh +0 -0
  94. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/pyflutter_ui/__init__.py +0 -0
  95. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/pyflutter_ui/app.py +0 -0
  96. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/pyflutter_ui/navigator.py +0 -0
  97. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/pyflutter_ui/scheduler.py +0 -0
  98. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/pyflutter_ui/theme.py +0 -0
  99. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/pyflutter_ui/ui/__init__.py +0 -0
  100. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/pyflutter_ui/ui/buttons.py +0 -0
  101. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/pyflutter_ui/ui/container.py +0 -0
  102. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/pyflutter_ui/ui/list_builder.py +0 -0
  103. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/pyflutter_ui/ui/progress.py +0 -0
  104. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/pyflutter_ui/ui/tables.py +0 -0
  105. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/pyflutter_ui/ui/widgets.py +0 -0
  106. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/table_stream/pattner/__init__.py +0 -0
  107. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/table_stream/sheet/__init__.py +0 -0
  108. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/table_stream/sheet/check_mod.py +0 -0
  109. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/table_stream/sheet/load.py +0 -0
  110. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/table_stream/sheet/options.py +0 -0
  111. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/table_stream/sheet/parse.py +0 -0
  112. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/table_stream/sheet/save.py +0 -0
  113. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/table_stream/state.py +1 -1
  114. {pyflutter_app-0.2.4 → pyflutter_app-0.2.7}/table_stream/workbook.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pyflutter_app
3
- Version: 0.2.4
3
+ Version: 0.2.7
4
4
  Summary: Bibliotecas Python para conversão de documentos, interface e processamento de tabelas.
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: openpyxl>=3.1.5
@@ -0,0 +1,6 @@
1
+ from .find_toi import extrair_uc_toi
2
+ from ._table_toi import HeaderTOI, TableTOI, LocalEntregaCarta, TipoCarta
3
+ from .common import BuilderConfigTOI, ConfigTOI
4
+ from .relatorio import (
5
+ CreateRelatorioTOI, TableTOI, ReadWriteTableTOI, load_files_toi
6
+ )
@@ -0,0 +1,151 @@
1
+ from __future__ import annotations
2
+ from enum import StrEnum
3
+ from typing import Any, Callable, TypeVar
4
+
5
+ from pandas import DataFrame
6
+
7
+ from table_stream import (
8
+ ArrayList, HashMapDict, TableMap, ColumnV, RowH, PathElement,
9
+ Directory, File, HeaderMetaData, concat_tables, ColumnNotFoundError,
10
+ )
11
+
12
+ from cartas.common import ConfigTOI, BuilderConfigTOI
13
+
14
+
15
+ class HeaderTOI(StrEnum):
16
+
17
+ UC = "uc"
18
+ TOI = "toi"
19
+ DAY = "day"
20
+ MON = "mon"
21
+ YEAR = "year"
22
+ DATE = "data_entrega"
23
+ LOCAL_ENTREGA = "local_entrega"
24
+ TIPO_DOC = "tipo_carta"
25
+ IS_FILE = "arquivo?"
26
+
27
+ FULL_PATH = HeaderMetaData.FILE_PATH.value
28
+ SRC = HeaderMetaData.PARENT_DIR.value
29
+ FILE_EXTENSION = HeaderMetaData.FILE_EXTENSION.value
30
+
31
+ HASH_FILE = HeaderMetaData.HASH_FILE.value
32
+ FILE_BASENAME = "basename"
33
+
34
+
35
+ class TipoCarta(StrEnum):
36
+
37
+ CARTA_CALCULO = "CARTA-CALCULO"
38
+
39
+
40
+ class LocalEntregaCarta(StrEnum):
41
+
42
+ OUTRO = "OUTRO"
43
+ MAOS = "MÃOS"
44
+ CORREIOS = "CORREIOS"
45
+ PORTAO = "PORTÃO"
46
+
47
+
48
+ class TableTOI(TableMap[HeaderTOI]):
49
+ """
50
+ Tabela para representar dados de cartas TOI.
51
+ """
52
+
53
+ def __init__(self, table_map: HashMapDict[HeaderTOI, ColumnV] | None = None) -> None:
54
+ super().__init__(table_map)
55
+
56
+ def rows(self) -> ArrayList[RowH[HeaderTOI, Any]]:
57
+ return super().rows()
58
+
59
+ def select_columns(self, header: list[HeaderTOI]) -> TableTOI:
60
+ final = TableTOI()
61
+
62
+ for h in header:
63
+ if not self.header().contains(h):
64
+ raise ColumnNotFoundError(f"Coluna não encontrada: {h}")
65
+ final.add(self.get(h))
66
+ return final
67
+
68
+ @staticmethod
69
+ def create_map_from_filename(filename: str) -> HashMapDict[HeaderTOI, str]:
70
+ data = HashMapDict()
71
+
72
+ try:
73
+ values = filename.split(" ")
74
+ if len(values) < 5:
75
+ return data
76
+ except:
77
+ return data
78
+ else:
79
+ for x in values:
80
+ if not x.isnumeric():
81
+ return data
82
+
83
+ data[HeaderTOI.UC] = values[0] # UC
84
+ data[HeaderTOI.TOI] = values[1] # TOI
85
+ data[HeaderTOI.DAY] = values[2] # DIA
86
+ data[HeaderTOI.MON] = values[3] # MÊS
87
+ data[HeaderTOI.YEAR] = values[4] # ANO
88
+ data[HeaderTOI.DATE] = f"{values[2]}/{values[3]}/{values[4]}"
89
+ return data
90
+
91
+ @classmethod
92
+ def create_table_from_path(cls, path: PathElement) -> TableTOI:
93
+ mp = cls.create_map_from_filename(path.name())
94
+ tb = cls.create_void_table()
95
+
96
+ for h in mp.header():
97
+ e = mp[h]
98
+ tb.get(h).add(e)
99
+
100
+ tb.get(HeaderTOI.FULL_PATH).add(path.absolute())
101
+ tb.get(HeaderTOI.IS_FILE).add("S" if path.is_file() else "N")
102
+ tb.get(HeaderTOI.TIPO_DOC).add(TipoCarta.CARTA_CALCULO.value)
103
+ tb.get(HeaderTOI.LOCAL_ENTREGA).add(LocalEntregaCarta.OUTRO.value)
104
+ tb.get(HeaderTOI.SRC).add(path.parent().absolute())
105
+ tb.get(HeaderTOI.FILE_EXTENSION).add(path.extension())
106
+ return tb
107
+
108
+ @classmethod
109
+ def create_void_table(cls) -> TableTOI:
110
+ """
111
+ Cria uma tabela toi vazia com todos os elementos de HeaderTOI
112
+ """
113
+ cols = [x for x in HeaderTOI]
114
+ columns_v = [ColumnV(c) for c in cols]
115
+ tb = cls()
116
+
117
+ for c in columns_v:
118
+ tb.add(c)
119
+ return tb
120
+
121
+ @classmethod
122
+ def create_from_files(cls, elements: ArrayList[PathElement]) -> TableTOI:
123
+
124
+ _path_element: PathElement
125
+ list_tables = ArrayList[TableTOI]()
126
+
127
+ for _path_element in elements:
128
+ current_tb = cls.create_table_from_path(_path_element)
129
+ if not current_tb.empty():
130
+ list_tables.append(current_tb)
131
+
132
+ if list_tables.empty():
133
+ return cls()
134
+
135
+ final = concat_tables(list_tables)
136
+ return cls(final._table_dict)
137
+
138
+ @classmethod
139
+ def create_from_data(cls, data: DataFrame) -> TableTOI:
140
+ columns_df = ArrayList(data.columns.tolist())
141
+ columns_toi = [x for x in HeaderTOI]
142
+ tb = cls()
143
+
144
+ for col_toi in columns_toi:
145
+ if not columns_df.contains(col_toi):
146
+ continue
147
+
148
+ elements = data[col_toi].astype("str").values.tolist()
149
+ col_v = ColumnV(col_toi, ArrayList(elements))
150
+ tb.add(col_v)
151
+ return tb
@@ -0,0 +1,68 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass
3
+
4
+ from table_stream import File, Directory, UserFileSystem
5
+
6
+
7
+ @dataclass
8
+ class ConfigTOI:
9
+
10
+ file_relatorio_toi: File
11
+ file_table_toi: File
12
+ dir_base_toi: Directory
13
+ work_dir: Directory
14
+
15
+
16
+ class BuilderConfigTOI(object):
17
+
18
+ _instance = None # Atributo de classe para armazenar a instância singleton
19
+
20
+ def __new__(cls, *args, **kwargs):
21
+ if cls._instance is None:
22
+ cls._instance = super(BuilderConfigTOI, cls).__new__(cls)
23
+ return cls._instance
24
+
25
+ def __init__(self) -> None:
26
+
27
+ # Garante que __init__ não será executado mais de uma vez
28
+ if hasattr(self, "_initialized") and self._initialized:
29
+ return
30
+
31
+ super().__init__()
32
+ self._initialized: bool = True
33
+ self._work_dir: Directory = (
34
+ UserFileSystem()
35
+ .get_user_documents()
36
+ .concat("RFA", True)
37
+ .concat("Cartas-TOI")
38
+ )
39
+
40
+ self._config = self._create()
41
+
42
+ @property
43
+ def dir_retorno_de_campo(self) -> Directory:
44
+ return self._work_dir.concat("Retorno-de-campo", True)
45
+
46
+ @property
47
+ def file_relatorio_toi(self) -> File:
48
+ return self._work_dir.concat("Relatorios", True).join_file("Relatorio-tois.xlsx")
49
+
50
+ @property
51
+ def file_table_toi(self) -> File:
52
+ return self._work_dir.concat("Relatorios", True).join_file("Tabela-tois.xlsx")
53
+
54
+ def _create(self) -> ConfigTOI:
55
+ return ConfigTOI(
56
+ work_dir=self._work_dir,
57
+ dir_base_toi=self.dir_retorno_de_campo,
58
+ file_relatorio_toi=self.file_relatorio_toi,
59
+ file_table_toi=self.file_table_toi,
60
+ )
61
+
62
+ def set_work_dir(self, d: Directory) -> BuilderConfigTOI:
63
+ self._work_dir = d
64
+ self._config = self._create()
65
+ return self
66
+
67
+ def builder(self) -> ConfigTOI:
68
+ return self._config
@@ -0,0 +1,27 @@
1
+ import re
2
+
3
+
4
+ # ============================================================#
5
+ # Extração de UC/TOI tolerante a falhas de OCR
6
+ # ============================================================#
7
+ #
8
+ # UC: 1305934 TOI: 193166923 ...
9
+ # UC: 1305934 TO! 193166923 ... (TOI virou TO!, ":" some)
10
+ # UC| 1305934 T0I: 193166923 ... (0 no lugar do O)
11
+ #
12
+
13
+ UC_TOI_PATTERN = re.compile(
14
+ r"U[C0]\s*[:;|!]?\s*(\d{4,10})" r".{0,60}?" r"T[O0][I1L!l]?\s*[:;|!]?\s*(\d{4,10})",
15
+ re.IGNORECASE | re.DOTALL,
16
+ )
17
+
18
+
19
+ def extrair_uc_toi(texto: str) -> tuple[str, str] | None:
20
+ """
21
+ Retorna (uc, toi) a partir do texto OCR completo de um arquivo,
22
+ ou None se o padrão não for encontrado.
23
+ """
24
+ m = UC_TOI_PATTERN.search(texto)
25
+ if not m:
26
+ return None
27
+ return m.group(1), m.group(2)
@@ -0,0 +1,350 @@
1
+ from ocrlib import (
2
+ TableOcr,
3
+ HeaderOcr,
4
+ DocumentInputStream,
5
+ ReadWriteTableOCR,
6
+ ControllerRelatorioOcr,
7
+ ColumnV,
8
+ ControllerOcr,
9
+ )
10
+
11
+ from whatsapp_files import TableWhatsApp, HeaderWhatsApp, CreateRelatorioWhatsApp
12
+
13
+ from table_stream import (
14
+ File,
15
+ Directory,
16
+ HashMapDict,
17
+ hashFile,
18
+ ColumnNotFoundError,
19
+ ArrayList,
20
+ PathElement,
21
+ TableMap,
22
+ RowH,
23
+ load_file_hash,
24
+ concat_tables,
25
+ create_table_from_file,
26
+ create_void_table_files,
27
+ )
28
+
29
+ import pandas as pd
30
+ from cartas._table_toi import HeaderTOI, TableTOI, TipoCarta, LocalEntregaCarta
31
+ from cartas.find_toi import extrair_uc_toi
32
+ from cartas.common import ConfigTOI, BuilderConfigTOI
33
+ from os import rename as rename_file
34
+
35
+
36
+ class ReadWriteTableTOI(object):
37
+ """
38
+ Leitura e escrita de dados na tabela OCR.
39
+ """
40
+
41
+ _instance = None # Atributo de classe para armazenar a instância singleton
42
+
43
+ def __new__(cls, *args, **kwargs):
44
+ if cls._instance is None:
45
+ cls._instance = super(ReadWriteTableTOI, cls).__new__(cls)
46
+ return cls._instance
47
+
48
+ def __init__(self) -> None:
49
+
50
+ # Garante que __init__ não será executado mais de uma vez
51
+ if hasattr(self, "_initialized") and self._initialized:
52
+ return
53
+
54
+ super().__init__()
55
+ self._initialized: bool = True
56
+ self.builder: BuilderConfigTOI = BuilderConfigTOI()
57
+
58
+ @property
59
+ def file_table_cache(self) -> File:
60
+ return BuilderConfigTOI().builder().file_table_toi
61
+
62
+ def load_table_cache(self) -> TableTOI:
63
+
64
+ f = self.file_table_cache
65
+
66
+ if not f.exists():
67
+ tb = TableTOI()
68
+ tb.add(ColumnV(HeaderTOI.UC))
69
+ tb.add(ColumnV(HeaderTOI.TOI))
70
+ tb.add(ColumnV(HeaderTOI.YEAR))
71
+ tb.add(ColumnV(HeaderTOI.MON))
72
+ tb.add(ColumnV(HeaderTOI.DAY))
73
+ tb.add(ColumnV(HeaderTOI.DATE))
74
+ tb.add(ColumnV(HeaderTOI.LOCAL_ENTREGA))
75
+ tb.add(ColumnV(HeaderTOI.TIPO_DOC))
76
+ tb.add(ColumnV(HeaderTOI.HASH_FILE))
77
+ return tb
78
+
79
+ data = pd.read_excel(f.absolute())
80
+ return TableTOI.create_from_data(data.astype("str"))
81
+
82
+ def save_table_cache(self, tb: TableTOI) -> None:
83
+ data = tb.to_dataframe()
84
+ path = self.file_table_cache.absolute()
85
+ tmp_file = f"{path}-tmp.xlsx"
86
+
87
+ print(f"Salvando ... {path}")
88
+ data.to_excel(tmp_file, index=False)
89
+ rename_file(tmp_file, path)
90
+
91
+
92
+ class CreateRelatorioTOI(object):
93
+ """
94
+ Cria uma tabela de Cartas TOI apartir dos chats do WhatsApp.
95
+ Conectando os arquivos das conversas aos textos extraídos via OCR.
96
+
97
+ TableWhatsApp() é usado para obter DATA e HORA do envio de um arquivo
98
+ no chat, pois a data de envio no chat e a data de entrega de uma carta em campo.
99
+ """
100
+
101
+ MAP_OCR_TO_TOI: HashMapDict[HeaderOcr, HeaderTOI] = HashMapDict(
102
+ {
103
+ HeaderOcr.FILE_PATH: HeaderTOI.FULL_PATH,
104
+ HeaderOcr.FILE_EXTENSION: HeaderTOI.FILE_EXTENSION,
105
+ HeaderOcr.FILE_BASENAME: HeaderTOI.FILE_BASENAME,
106
+ HeaderOcr.HASH_FILE: HeaderTOI.HASH_FILE,
107
+ }
108
+ )
109
+
110
+ def __init__(self) -> None:
111
+
112
+ self.relatorio_ocr: ControllerRelatorioOcr = ControllerRelatorioOcr()
113
+ self.relatorio_whatsapp: CreateRelatorioWhatsApp = CreateRelatorioWhatsApp()
114
+
115
+ def load_table_whatsapp(self) -> TableWhatsApp:
116
+ return self.relatorio_whatsapp.load_cache_table()
117
+
118
+ def find_on_cache(self, map: HashMapDict[hashFile, File]) -> TableTOI | None:
119
+ """
120
+ Gera uma tabela TOI apartir da tabela TOI em cache sem executar
121
+ o filtro de texto em OCR com expressão regular. Apenas gera uma
122
+ tabela consultando a base TOI em cache
123
+ """
124
+
125
+ if map.is_empty():
126
+ return None
127
+
128
+ tb_cache = ReadWriteTableTOI().load_table_cache()
129
+ final = TableTOI()
130
+
131
+ header = map.header()
132
+ h: hashFile
133
+
134
+ for h in header:
135
+ f = map.get_value(h)
136
+
137
+ content = tb_cache.search(HeaderTOI.HASH_FILE, h)
138
+ if content.empty():
139
+ continue
140
+
141
+ content_row = content.get_row_at(0)
142
+ content_row.set(HeaderTOI.FILE_EXTENSION, f.extension() or ".nan")
143
+ content_row.set(HeaderTOI.FILE_BASENAME, f.basename())
144
+ content_row.set(HeaderTOI.IS_FILE, "S" if f.is_file() else "N")
145
+ content_row.set(HeaderTOI.FULL_PATH, f.absolute())
146
+ content_row.set(HeaderTOI.SRC, f.parent().absolute())
147
+ final.add_row(content_row)
148
+
149
+ return final
150
+
151
+ def create_from_map(
152
+ self, map: HashMapDict[hashFile, File], *, ignore_null: bool = True
153
+ ) -> TableTOI | None:
154
+ """
155
+ I) Usa a HASH MD5 dos arquivos para buscar a data de envio do arquivo na
156
+ tabela whatsapp;
157
+
158
+ II) Gera um relatório OCR [CreateRelatorioExcelOcr()] com os metadados básicos
159
+ de cada arquivo;
160
+
161
+ III) Obtem a UC e TOI de cada arquivo.
162
+
163
+ IV) Retorna uma tabela apartir dos dados gerados.
164
+
165
+ Observação:
166
+ Se o parametro ignore_null for True as linhas que contém UC e TOI inválidos
167
+ serão ignorados.
168
+ """
169
+
170
+ if map.is_empty():
171
+ return None
172
+
173
+ # Dados OCR completos de cada arquivo do parâmetro map, esses arquivos
174
+ # serão comparados com a tabela whatsapp para filtar a data de envio no chat.
175
+ table_ocr: TableOcr = self.relatorio_ocr.create_all(map)
176
+ table_whatsapp: TableWhatsApp = self.load_table_whatsapp()
177
+
178
+ if table_ocr is None:
179
+ return None
180
+
181
+ if table_ocr.is_empty():
182
+ return None
183
+
184
+ # Cada arquivo gera/extrai a sua própria tabela, ao final essa
185
+ # lista de tabelas serão concatenadas em uma tabela única.
186
+ list_tables_toi: ArrayList[TableTOI] = ArrayList()
187
+ keys = map.header()
188
+ total = keys.size()
189
+
190
+ print(f"Criando relatório TOI de {total} arquivos")
191
+ k: hashFile
192
+ f: File
193
+
194
+ for n, k in enumerate(keys):
195
+ f = map.get_value(k)
196
+
197
+ print(f"[FILTRANDO] [{n+1}/{total}] {f.basename()}")
198
+
199
+ current_table_ocr: TableOcr = table_ocr.search(HeaderOcr.HASH_FILE, k)
200
+ text_ocr: str = None
201
+
202
+ if not current_table_ocr.is_empty():
203
+ text_ocr = current_table_ocr.to_string(HeaderOcr.TEXT)
204
+
205
+ txt_uc_toi: tuple | None = (
206
+ extrair_uc_toi(text_ocr) if text_ocr is not None else None
207
+ )
208
+
209
+ if txt_uc_toi is None:
210
+ if ignore_null:
211
+ continue
212
+
213
+ uc = TableTOI.NULL_STRING
214
+ toi = TableTOI.NULL_STRING
215
+ year = TableTOI.NULL_STRING
216
+ mon = TableTOI.NULL_STRING
217
+ day = TableTOI.NULL_STRING
218
+ dt: str = TableTOI.NULL_STRING
219
+
220
+ if txt_uc_toi is not None:
221
+ uc = txt_uc_toi[0]
222
+ toi = txt_uc_toi[1]
223
+
224
+ current_table_whatsapp = table_whatsapp.search(HeaderWhatsApp.hash_md5, k)
225
+
226
+ if not current_table_whatsapp.empty():
227
+ dt = current_table_whatsapp.get_row_at(0).get_date().get_first()
228
+ day = dt.split(" ")[0]
229
+ mon = dt.split(" ")[1]
230
+ year = dt.split(" ")[2]
231
+
232
+ tb_toi = TableTOI()
233
+
234
+ tb_toi.add(ColumnV(HeaderTOI.UC, ArrayList([uc])))
235
+ tb_toi.add(ColumnV(HeaderTOI.TOI, ArrayList([toi])))
236
+ tb_toi.add(ColumnV(HeaderTOI.YEAR, ArrayList([year])))
237
+ tb_toi.add(ColumnV(HeaderTOI.MON, ArrayList([mon])))
238
+ tb_toi.add(ColumnV(HeaderTOI.DAY, ArrayList([day])))
239
+ tb_toi.add(ColumnV(HeaderTOI.DATE, ArrayList([dt])))
240
+
241
+ tb_toi.add(
242
+ ColumnV(HeaderTOI.FILE_EXTENSION, ArrayList([f.extension() or ".nan"]))
243
+ )
244
+ tb_toi.add(ColumnV(HeaderTOI.FILE_BASENAME, ArrayList([f.basename()])))
245
+ tb_toi.add(ColumnV(HeaderTOI.HASH_FILE, ArrayList([k])))
246
+ tb_toi.add(ColumnV(HeaderTOI.FULL_PATH, ArrayList([f.absolute()])))
247
+ tb_toi.add(
248
+ ColumnV(HeaderTOI.IS_FILE, ArrayList(["S" if f.is_file() else "N"]))
249
+ )
250
+ tb_toi.add(ColumnV(HeaderTOI.SRC, ArrayList([f.dirname()])))
251
+
252
+ tb_toi.add(
253
+ ColumnV(HeaderTOI.TIPO_DOC, ArrayList([TipoCarta.CARTA_CALCULO]))
254
+ )
255
+ tb_toi.add(
256
+ ColumnV(HeaderTOI.LOCAL_ENTREGA, ArrayList([LocalEntregaCarta.OUTRO]))
257
+ )
258
+
259
+ list_tables_toi.add(tb_toi)
260
+
261
+ if list_tables_toi.empty():
262
+ return None
263
+
264
+ final = TableTOI.create_void_table()
265
+ list_tables_toi.for_each(lambda t: final.merge(t))
266
+ return final
267
+
268
+ @staticmethod
269
+ def filter_uc_toi(hf: hashFile, table_ocr_file: TableOcr) -> tuple[str, str] | None:
270
+ """
271
+ Filtra UC e TOI de uma carta apartir do texto OCR extraído.
272
+ """
273
+ tb_current_hash = table_ocr_file.search(HeaderOcr.HASH_FILE, hf)
274
+ if tb_current_hash.is_empty():
275
+ return None
276
+
277
+ values = tb_current_hash.get(HeaderOcr.TEXT)._elements
278
+
279
+ for v in values:
280
+ txt = extrair_uc_toi(v)
281
+ if txt is not None:
282
+ return txt
283
+ return None
284
+
285
+
286
+ def load_files_toi(files: ArrayList[File]) -> TableTOI | None:
287
+ """
288
+ Analisa arquivos TOI apartir da HASH MD5, compara o texto na tabela OCR e inclui
289
+ UC e TOI na tabela TOI principal e ao final retorna os dados no formato de tabela TOI.
290
+ """
291
+ if files.empty():
292
+ print(f"[DEBUG]: load_files_toi() lista de arquivos vazia!")
293
+ return None
294
+
295
+ map = HashMapDict[hashFile, File]()
296
+ files.for_each(lambda f: map.set_value(load_file_hash(f), f))
297
+
298
+ content_table = CreateRelatorioTOI().create_from_map(map)
299
+ if content_table is None:
300
+ return None
301
+ if content_table.empty():
302
+ return None
303
+
304
+ # Selecionar apenas algumas colunas para salvar em cache.
305
+ content_tb_merge = content_table.select_columns(
306
+ [
307
+ HeaderTOI.UC,
308
+ HeaderTOI.TOI,
309
+ HeaderTOI.YEAR,
310
+ HeaderTOI.MON,
311
+ HeaderTOI.DAY,
312
+ HeaderTOI.DATE,
313
+ HeaderTOI.LOCAL_ENTREGA,
314
+ HeaderTOI.TIPO_DOC,
315
+ HeaderTOI.HASH_FILE,
316
+ ]
317
+ )
318
+
319
+ # Filtar UCs validas
320
+ df_merge = content_tb_merge.to_dataframe().astype(str)
321
+ df_merge = df_merge[df_merge[HeaderTOI.UC] != TableTOI.NULL_STRING]
322
+ df_merge.drop_duplicates(subset=[HeaderTOI.HASH_FILE], inplace=True)
323
+
324
+ rw = ReadWriteTableTOI()
325
+ tb_cache_toi: TableTOI = rw.load_table_cache()
326
+ df_cache_toi = (
327
+ pd.DataFrame()
328
+ if tb_cache_toi.empty()
329
+ else tb_cache_toi.to_dataframe().astype(str)
330
+ )
331
+
332
+ df_cache = (
333
+ pd.concat([df_cache_toi, df_merge.astype(str)])
334
+ if not df_cache_toi.empty
335
+ else df_merge.astype(str)
336
+ )
337
+ df_cache.drop_duplicates(subset=[HeaderTOI.HASH_FILE]).astype(str)
338
+
339
+ rw.save_table_cache(TableTOI.create_from_data(df_cache))
340
+ return content_table
341
+
342
+
343
+ class ControllerToi(object):
344
+
345
+ def __init__(self) -> None:
346
+ self.conf: ConfigTOI = BuilderConfigTOI().builder()
347
+ self.ocr: ControllerOcr = ControllerOcr()
348
+
349
+ def load_files_toi(self):
350
+ pass
@@ -0,0 +1 @@
1
+ from .run_app_convert import main as run_ui_app_convert
@@ -0,0 +1,9 @@
1
+ from converter import run_app_convert
2
+
3
+ def main() -> None:
4
+ run_app_convert.main()
5
+
6
+
7
+ if __name__ == '__main__':
8
+ main()
9
+
@@ -1,4 +1,4 @@
1
- # converter/excel/page_edit.py
1
+ # converter/home_page/_page_edit.py
2
2
  from __future__ import annotations
3
3
 
4
4
  from converter.util import (
@@ -207,13 +207,12 @@ class _HomePageState(StatelessWidget):
207
207
  Seta o DataFrame() da página atual como propriedade do ControllerForms()
208
208
  antes de carregar a página.
209
209
  """
210
-
211
- forms_controller: ControllerForms = context.read(ControllerForms)
212
- forms_controller.set_data(controller.data_notifier.value)
213
-
214
- if not forms_controller.forms_state.data_is_valid():
215
- messagebox.showerror("Erro", "Tabela TOI inválida")
216
- return
210
+ #df = controller.data_notifier.value
211
+ #forms_controller: ControllerForms = context.read(ControllerForms)
212
+ #forms_controller.set_data(df)
213
+ #if not forms_controller.forms_state.data_is_valid():
214
+ # messagebox.showerror("Erro", "Tabela TOI inválida")
215
+ # return
217
216
 
218
217
  context.navigator.push(PageRespondsForms())
219
218