pyflutter-app 0.2.5__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.
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/.idea/pyflutter_app.iml +1 -1
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/PKG-INFO +1 -5
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/cartas/__init__.py +1 -1
- pyflutter_app-0.2.5/cartas/table_toi.py → pyflutter_app-0.2.7/cartas/_table_toi.py +7 -7
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/cartas/relatorio.py +127 -67
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/page_forms/common.py +10 -6
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/page_forms/controller_forms.py +11 -1
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/page_forms/model_forms.py +8 -5
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/page_forms/service.py +103 -11
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/mediator.py +4 -4
- pyflutter_app-0.2.7/ocrlib/__init__.py +54 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/ocrlib/_common.py +19 -25
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/ocrlib/_pdf_convert.py +34 -30
- pyflutter_app-0.2.7/ocrlib/_table_ocr.py +578 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/ocrlib/_tesseract.py +28 -10
- pyflutter_app-0.2.7/ocrlib/erros.py +5 -0
- pyflutter_app-0.2.5/ocrlib/ocr.py → pyflutter_app-0.2.7/ocrlib/relatorio_ocr.py +283 -150
- pyflutter_app-0.2.7/ocrlib/util.py +29 -0
- pyflutter_app-0.2.7/pyproject.toml +34 -0
- pyflutter_app-0.2.5/pyproject.toml → pyflutter_app-0.2.7/pyproject.toml.back +8 -1
- pyflutter_app-0.2.7/table_stream/__init__.py +92 -0
- pyflutter_app-0.2.7/table_stream/erros.py +162 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/table_stream/hash_map.py +53 -223
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/table_stream/sysfiles.py +192 -169
- pyflutter_app-0.2.7/table_stream/table.py +835 -0
- pyflutter_app-0.2.7/test.py +36 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/uv.lock +5 -241
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/whatsapp_files/_table_whatsapp.py +5 -5
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/whatsapp_files/stream_files.py +3 -3
- pyflutter_app-0.2.5/ocrlib/__init__.py +0 -24
- pyflutter_app-0.2.5/ocrlib/_table_ocr.py +0 -526
- pyflutter_app-0.2.5/ocrlib/erros.py +0 -0
- pyflutter_app-0.2.5/ocrlib/util.py +0 -12
- pyflutter_app-0.2.5/table_stream/__init__.py +0 -33
- pyflutter_app-0.2.5/table_stream/erros.py +0 -115
- pyflutter_app-0.2.5/table_stream/table.py +0 -573
- pyflutter_app-0.2.5/test.py +0 -92
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/.gitignore +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/.idea/.gitignore +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/.idea/inspectionProfiles/Project_Default.xml +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/.idea/misc.xml +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/.idea/modules.xml +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/.idea/vcs.xml +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/README.md +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/cartas/common.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/cartas/erros.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/cartas/find_toi.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/__init__.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/__main__.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/assets/forms_config.json +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/config_app.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/home_page/__init__.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/home_page/_page_edit.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/home_page/controller.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/home_page/model.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/home_page/view.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/lib_toi.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/page_forms/Diagnorstico.txt +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/page_forms/__init__.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/page_forms/config.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/page_forms/diagnose_forms.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/page_forms/view_forms.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/run_app_convert.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/table_widget.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/util.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/whatsapp/__init__.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/converter/whatsapp/model.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/export_app.sh +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/local_build/linux.sh +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/local_build/send.sh +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/main.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/mvc/controller.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/mvc/model.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/mvc/view.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/new-export_app.sh +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/ocrlib/export_ocr.sh +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/pyflutter_ui/__init__.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/pyflutter_ui/app.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/pyflutter_ui/file_picker.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/pyflutter_ui/navigator.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/pyflutter_ui/scheduler.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/pyflutter_ui/theme.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/pyflutter_ui/ui/__init__.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/pyflutter_ui/ui/buttons.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/pyflutter_ui/ui/container.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/pyflutter_ui/ui/core.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/pyflutter_ui/ui/list_builder.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/pyflutter_ui/ui/progress.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/pyflutter_ui/ui/tables.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/pyflutter_ui/ui/widgets.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/table_stream/notifier.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/table_stream/pattner/__init__.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/table_stream/pattner/adapter.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/table_stream/sheet/__init__.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/table_stream/sheet/check_mod.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/table_stream/sheet/load.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/table_stream/sheet/options.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/table_stream/sheet/parse.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/table_stream/sheet/save.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/table_stream/state.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/table_stream/thread.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/table_stream/workbook.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/whatsapp_files/__init__.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/whatsapp_files/common.py +0 -0
- {pyflutter_app-0.2.5 → pyflutter_app-0.2.7}/whatsapp_files/erros.py +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<content url="file://$MODULE_DIR$">
|
|
5
5
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
|
6
6
|
</content>
|
|
7
|
-
<orderEntry type="jdk" jdkName="
|
|
7
|
+
<orderEntry type="jdk" jdkName="~/GIT/pyflutter/.venv" jdkType="Python SDK" />
|
|
8
8
|
<orderEntry type="sourceFolder" forTests="false" />
|
|
9
9
|
</component>
|
|
10
10
|
<component name="PyDocumentationSettings">
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pyflutter_app
|
|
3
|
-
Version: 0.2.
|
|
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
|
-
Requires-Dist: opencv-python>=5.0.0.93
|
|
7
6
|
Requires-Dist: openpyxl>=3.1.5
|
|
8
7
|
Requires-Dist: pandas-stubs~=3.0.3
|
|
9
8
|
Requires-Dist: pandas>=3.0.0
|
|
10
|
-
Requires-Dist: playwright>=1.63.0
|
|
11
|
-
Requires-Dist: pymupdf>=1.28.2
|
|
12
|
-
Requires-Dist: pytesseract>=0.3.13
|
|
13
9
|
Description-Content-Type: text/markdown
|
|
14
10
|
|
|
15
11
|
# pyflutter
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from .find_toi import extrair_uc_toi
|
|
2
|
-
from .
|
|
2
|
+
from ._table_toi import HeaderTOI, TableTOI, LocalEntregaCarta, TipoCarta
|
|
3
3
|
from .common import BuilderConfigTOI, ConfigTOI
|
|
4
4
|
from .relatorio import (
|
|
5
5
|
CreateRelatorioTOI, TableTOI, ReadWriteTableTOI, load_files_toi
|
|
@@ -5,7 +5,7 @@ from typing import Any, Callable, TypeVar
|
|
|
5
5
|
from pandas import DataFrame
|
|
6
6
|
|
|
7
7
|
from table_stream import (
|
|
8
|
-
ArrayList, HashMapDict,
|
|
8
|
+
ArrayList, HashMapDict, TableMap, ColumnV, RowH, PathElement,
|
|
9
9
|
Directory, File, HeaderMetaData, concat_tables, ColumnNotFoundError,
|
|
10
10
|
)
|
|
11
11
|
|
|
@@ -24,11 +24,11 @@ class HeaderTOI(StrEnum):
|
|
|
24
24
|
TIPO_DOC = "tipo_carta"
|
|
25
25
|
IS_FILE = "arquivo?"
|
|
26
26
|
|
|
27
|
-
FULL_PATH = HeaderMetaData.
|
|
28
|
-
SRC = HeaderMetaData.
|
|
29
|
-
FILE_EXTENSION = HeaderMetaData.
|
|
27
|
+
FULL_PATH = HeaderMetaData.FILE_PATH.value
|
|
28
|
+
SRC = HeaderMetaData.PARENT_DIR.value
|
|
29
|
+
FILE_EXTENSION = HeaderMetaData.FILE_EXTENSION.value
|
|
30
30
|
|
|
31
|
-
HASH_FILE = HeaderMetaData.
|
|
31
|
+
HASH_FILE = HeaderMetaData.HASH_FILE.value
|
|
32
32
|
FILE_BASENAME = "basename"
|
|
33
33
|
|
|
34
34
|
|
|
@@ -45,7 +45,7 @@ class LocalEntregaCarta(StrEnum):
|
|
|
45
45
|
PORTAO = "PORTÃO"
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
class TableTOI(
|
|
48
|
+
class TableTOI(TableMap[HeaderTOI]):
|
|
49
49
|
"""
|
|
50
50
|
Tabela para representar dados de cartas TOI.
|
|
51
51
|
"""
|
|
@@ -133,7 +133,7 @@ class TableTOI(TableElements[HeaderTOI]):
|
|
|
133
133
|
return cls()
|
|
134
134
|
|
|
135
135
|
final = concat_tables(list_tables)
|
|
136
|
-
return cls(final.
|
|
136
|
+
return cls(final._table_dict)
|
|
137
137
|
|
|
138
138
|
@classmethod
|
|
139
139
|
def create_from_data(cls, data: DataFrame) -> TableTOI:
|
|
@@ -1,18 +1,33 @@
|
|
|
1
1
|
from ocrlib import (
|
|
2
|
-
TableOcr,
|
|
3
|
-
|
|
2
|
+
TableOcr,
|
|
3
|
+
HeaderOcr,
|
|
4
|
+
DocumentInputStream,
|
|
5
|
+
ReadWriteTableOCR,
|
|
6
|
+
ControllerRelatorioOcr,
|
|
7
|
+
ColumnV,
|
|
8
|
+
ControllerOcr,
|
|
4
9
|
)
|
|
5
10
|
|
|
6
11
|
from whatsapp_files import TableWhatsApp, HeaderWhatsApp, CreateRelatorioWhatsApp
|
|
7
12
|
|
|
8
13
|
from table_stream import (
|
|
9
|
-
File,
|
|
10
|
-
|
|
11
|
-
|
|
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,
|
|
12
27
|
)
|
|
13
28
|
|
|
14
29
|
import pandas as pd
|
|
15
|
-
from cartas.
|
|
30
|
+
from cartas._table_toi import HeaderTOI, TableTOI, TipoCarta, LocalEntregaCarta
|
|
16
31
|
from cartas.find_toi import extrair_uc_toi
|
|
17
32
|
from cartas.common import ConfigTOI, BuilderConfigTOI
|
|
18
33
|
from os import rename as rename_file
|
|
@@ -39,11 +54,11 @@ class ReadWriteTableTOI(object):
|
|
|
39
54
|
super().__init__()
|
|
40
55
|
self._initialized: bool = True
|
|
41
56
|
self.builder: BuilderConfigTOI = BuilderConfigTOI()
|
|
42
|
-
|
|
57
|
+
|
|
43
58
|
@property
|
|
44
59
|
def file_table_cache(self) -> File:
|
|
45
60
|
return BuilderConfigTOI().builder().file_table_toi
|
|
46
|
-
|
|
61
|
+
|
|
47
62
|
def load_table_cache(self) -> TableTOI:
|
|
48
63
|
|
|
49
64
|
f = self.file_table_cache
|
|
@@ -79,7 +94,7 @@ class CreateRelatorioTOI(object):
|
|
|
79
94
|
Cria uma tabela de Cartas TOI apartir dos chats do WhatsApp.
|
|
80
95
|
Conectando os arquivos das conversas aos textos extraídos via OCR.
|
|
81
96
|
|
|
82
|
-
TableWhatsApp() é usado para obter DATA e HORA do envio de um arquivo
|
|
97
|
+
TableWhatsApp() é usado para obter DATA e HORA do envio de um arquivo
|
|
83
98
|
no chat, pois a data de envio no chat e a data de entrega de uma carta em campo.
|
|
84
99
|
"""
|
|
85
100
|
|
|
@@ -94,53 +109,62 @@ class CreateRelatorioTOI(object):
|
|
|
94
109
|
|
|
95
110
|
def __init__(self) -> None:
|
|
96
111
|
|
|
97
|
-
self.relatorio_ocr:
|
|
112
|
+
self.relatorio_ocr: ControllerRelatorioOcr = ControllerRelatorioOcr()
|
|
98
113
|
self.relatorio_whatsapp: CreateRelatorioWhatsApp = CreateRelatorioWhatsApp()
|
|
99
114
|
|
|
100
115
|
def load_table_whatsapp(self) -> TableWhatsApp:
|
|
101
116
|
return self.relatorio_whatsapp.load_cache_table()
|
|
102
|
-
|
|
117
|
+
|
|
103
118
|
def find_on_cache(self, map: HashMapDict[hashFile, File]) -> TableTOI | None:
|
|
104
119
|
"""
|
|
105
120
|
Gera uma tabela TOI apartir da tabela TOI em cache sem executar
|
|
106
|
-
o filtro de texto em OCR com expressão regular.
|
|
121
|
+
o filtro de texto em OCR com expressão regular. Apenas gera uma
|
|
122
|
+
tabela consultando a base TOI em cache
|
|
107
123
|
"""
|
|
108
|
-
|
|
124
|
+
|
|
109
125
|
if map.is_empty():
|
|
110
126
|
return None
|
|
111
|
-
|
|
127
|
+
|
|
112
128
|
tb_cache = ReadWriteTableTOI().load_table_cache()
|
|
113
129
|
final = TableTOI()
|
|
114
|
-
|
|
130
|
+
|
|
115
131
|
header = map.header()
|
|
116
132
|
h: hashFile
|
|
117
|
-
|
|
133
|
+
|
|
118
134
|
for h in header:
|
|
119
135
|
f = map.get_value(h)
|
|
120
|
-
|
|
121
|
-
content = tb_cache.
|
|
136
|
+
|
|
137
|
+
content = tb_cache.search(HeaderTOI.HASH_FILE, h)
|
|
122
138
|
if content.empty():
|
|
123
139
|
continue
|
|
124
|
-
|
|
140
|
+
|
|
125
141
|
content_row = content.get_row_at(0)
|
|
126
|
-
content_row.set(HeaderTOI.FILE_EXTENSION, f.extension() or
|
|
142
|
+
content_row.set(HeaderTOI.FILE_EXTENSION, f.extension() or ".nan")
|
|
127
143
|
content_row.set(HeaderTOI.FILE_BASENAME, f.basename())
|
|
128
144
|
content_row.set(HeaderTOI.IS_FILE, "S" if f.is_file() else "N")
|
|
129
145
|
content_row.set(HeaderTOI.FULL_PATH, f.absolute())
|
|
130
146
|
content_row.set(HeaderTOI.SRC, f.parent().absolute())
|
|
131
147
|
final.add_row(content_row)
|
|
132
|
-
|
|
148
|
+
|
|
133
149
|
return final
|
|
134
150
|
|
|
135
|
-
def create_from_map(
|
|
151
|
+
def create_from_map(
|
|
152
|
+
self, map: HashMapDict[hashFile, File], *, ignore_null: bool = True
|
|
153
|
+
) -> TableTOI | None:
|
|
136
154
|
"""
|
|
137
155
|
I) Usa a HASH MD5 dos arquivos para buscar a data de envio do arquivo na
|
|
138
|
-
tabela whatsapp;
|
|
139
|
-
|
|
140
|
-
II) Gera um relatório OCR [CreateRelatorioExcelOcr()] com os metadados básicos
|
|
141
|
-
de cada arquivo;
|
|
142
|
-
|
|
156
|
+
tabela whatsapp;
|
|
157
|
+
|
|
158
|
+
II) Gera um relatório OCR [CreateRelatorioExcelOcr()] com os metadados básicos
|
|
159
|
+
de cada arquivo;
|
|
160
|
+
|
|
143
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.
|
|
144
168
|
"""
|
|
145
169
|
|
|
146
170
|
if map.is_empty():
|
|
@@ -154,7 +178,7 @@ class CreateRelatorioTOI(object):
|
|
|
154
178
|
if table_ocr is None:
|
|
155
179
|
return None
|
|
156
180
|
|
|
157
|
-
if table_ocr.
|
|
181
|
+
if table_ocr.is_empty():
|
|
158
182
|
return None
|
|
159
183
|
|
|
160
184
|
# Cada arquivo gera/extrai a sua própria tabela, ao final essa
|
|
@@ -163,7 +187,7 @@ class CreateRelatorioTOI(object):
|
|
|
163
187
|
keys = map.header()
|
|
164
188
|
total = keys.size()
|
|
165
189
|
|
|
166
|
-
print(f
|
|
190
|
+
print(f"Criando relatório TOI de {total} arquivos")
|
|
167
191
|
k: hashFile
|
|
168
192
|
f: File
|
|
169
193
|
|
|
@@ -172,14 +196,16 @@ class CreateRelatorioTOI(object):
|
|
|
172
196
|
|
|
173
197
|
print(f"[FILTRANDO] [{n+1}/{total}] {f.basename()}")
|
|
174
198
|
|
|
175
|
-
current_table_ocr: TableOcr = table_ocr.
|
|
199
|
+
current_table_ocr: TableOcr = table_ocr.search(HeaderOcr.HASH_FILE, k)
|
|
176
200
|
text_ocr: str = None
|
|
177
|
-
|
|
178
|
-
if not current_table_ocr.
|
|
201
|
+
|
|
202
|
+
if not current_table_ocr.is_empty():
|
|
179
203
|
text_ocr = current_table_ocr.to_string(HeaderOcr.TEXT)
|
|
180
204
|
|
|
181
|
-
txt_uc_toi: tuple | None =
|
|
182
|
-
|
|
205
|
+
txt_uc_toi: tuple | None = (
|
|
206
|
+
extrair_uc_toi(text_ocr) if text_ocr is not None else None
|
|
207
|
+
)
|
|
208
|
+
|
|
183
209
|
if txt_uc_toi is None:
|
|
184
210
|
if ignore_null:
|
|
185
211
|
continue
|
|
@@ -194,39 +220,47 @@ class CreateRelatorioTOI(object):
|
|
|
194
220
|
if txt_uc_toi is not None:
|
|
195
221
|
uc = txt_uc_toi[0]
|
|
196
222
|
toi = txt_uc_toi[1]
|
|
197
|
-
|
|
198
|
-
current_table_whatsapp = table_whatsapp.
|
|
199
|
-
|
|
223
|
+
|
|
224
|
+
current_table_whatsapp = table_whatsapp.search(HeaderWhatsApp.hash_md5, k)
|
|
225
|
+
|
|
200
226
|
if not current_table_whatsapp.empty():
|
|
201
227
|
dt = current_table_whatsapp.get_row_at(0).get_date().get_first()
|
|
202
|
-
day = dt.split(
|
|
203
|
-
mon = dt.split(
|
|
204
|
-
year = dt.split(
|
|
228
|
+
day = dt.split(" ")[0]
|
|
229
|
+
mon = dt.split(" ")[1]
|
|
230
|
+
year = dt.split(" ")[2]
|
|
205
231
|
|
|
206
232
|
tb_toi = TableTOI()
|
|
207
|
-
|
|
233
|
+
|
|
208
234
|
tb_toi.add(ColumnV(HeaderTOI.UC, ArrayList([uc])))
|
|
209
235
|
tb_toi.add(ColumnV(HeaderTOI.TOI, ArrayList([toi])))
|
|
210
236
|
tb_toi.add(ColumnV(HeaderTOI.YEAR, ArrayList([year])))
|
|
211
237
|
tb_toi.add(ColumnV(HeaderTOI.MON, ArrayList([mon])))
|
|
212
238
|
tb_toi.add(ColumnV(HeaderTOI.DAY, ArrayList([day])))
|
|
213
239
|
tb_toi.add(ColumnV(HeaderTOI.DATE, ArrayList([dt])))
|
|
214
|
-
|
|
215
|
-
tb_toi.add(
|
|
240
|
+
|
|
241
|
+
tb_toi.add(
|
|
242
|
+
ColumnV(HeaderTOI.FILE_EXTENSION, ArrayList([f.extension() or ".nan"]))
|
|
243
|
+
)
|
|
216
244
|
tb_toi.add(ColumnV(HeaderTOI.FILE_BASENAME, ArrayList([f.basename()])))
|
|
217
245
|
tb_toi.add(ColumnV(HeaderTOI.HASH_FILE, ArrayList([k])))
|
|
218
246
|
tb_toi.add(ColumnV(HeaderTOI.FULL_PATH, ArrayList([f.absolute()])))
|
|
219
|
-
tb_toi.add(
|
|
247
|
+
tb_toi.add(
|
|
248
|
+
ColumnV(HeaderTOI.IS_FILE, ArrayList(["S" if f.is_file() else "N"]))
|
|
249
|
+
)
|
|
220
250
|
tb_toi.add(ColumnV(HeaderTOI.SRC, ArrayList([f.dirname()])))
|
|
221
|
-
|
|
222
|
-
tb_toi.add(
|
|
223
|
-
|
|
224
|
-
|
|
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
|
+
|
|
225
259
|
list_tables_toi.add(tb_toi)
|
|
226
|
-
|
|
260
|
+
|
|
227
261
|
if list_tables_toi.empty():
|
|
228
262
|
return None
|
|
229
|
-
|
|
263
|
+
|
|
230
264
|
final = TableTOI.create_void_table()
|
|
231
265
|
list_tables_toi.for_each(lambda t: final.merge(t))
|
|
232
266
|
return final
|
|
@@ -236,11 +270,11 @@ class CreateRelatorioTOI(object):
|
|
|
236
270
|
"""
|
|
237
271
|
Filtra UC e TOI de uma carta apartir do texto OCR extraído.
|
|
238
272
|
"""
|
|
239
|
-
tb_current_hash = table_ocr_file.
|
|
240
|
-
if tb_current_hash.
|
|
273
|
+
tb_current_hash = table_ocr_file.search(HeaderOcr.HASH_FILE, hf)
|
|
274
|
+
if tb_current_hash.is_empty():
|
|
241
275
|
return None
|
|
242
276
|
|
|
243
|
-
values = tb_current_hash.get(HeaderOcr.TEXT).
|
|
277
|
+
values = tb_current_hash.get(HeaderOcr.TEXT)._elements
|
|
244
278
|
|
|
245
279
|
for v in values:
|
|
246
280
|
txt = extrair_uc_toi(v)
|
|
@@ -257,34 +291,60 @@ def load_files_toi(files: ArrayList[File]) -> TableTOI | None:
|
|
|
257
291
|
if files.empty():
|
|
258
292
|
print(f"[DEBUG]: load_files_toi() lista de arquivos vazia!")
|
|
259
293
|
return None
|
|
260
|
-
|
|
294
|
+
|
|
261
295
|
map = HashMapDict[hashFile, File]()
|
|
262
296
|
files.for_each(lambda f: map.set_value(load_file_hash(f), f))
|
|
263
|
-
|
|
297
|
+
|
|
264
298
|
content_table = CreateRelatorioTOI().create_from_map(map)
|
|
265
299
|
if content_table is None:
|
|
266
300
|
return None
|
|
267
301
|
if content_table.empty():
|
|
268
302
|
return None
|
|
269
|
-
|
|
303
|
+
|
|
270
304
|
# Selecionar apenas algumas colunas para salvar em cache.
|
|
271
|
-
content_tb_merge = content_table.select_columns(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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
|
+
|
|
277
319
|
# Filtar UCs validas
|
|
278
320
|
df_merge = content_tb_merge.to_dataframe().astype(str)
|
|
279
321
|
df_merge = df_merge[df_merge[HeaderTOI.UC] != TableTOI.NULL_STRING]
|
|
280
322
|
df_merge.drop_duplicates(subset=[HeaderTOI.HASH_FILE], inplace=True)
|
|
281
|
-
|
|
323
|
+
|
|
282
324
|
rw = ReadWriteTableTOI()
|
|
283
325
|
tb_cache_toi: TableTOI = rw.load_table_cache()
|
|
284
|
-
df_cache_toi =
|
|
285
|
-
|
|
286
|
-
|
|
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
|
+
)
|
|
287
337
|
df_cache.drop_duplicates(subset=[HeaderTOI.HASH_FILE]).astype(str)
|
|
288
|
-
|
|
338
|
+
|
|
289
339
|
rw.save_table_cache(TableTOI.create_from_data(df_cache))
|
|
290
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
|
|
@@ -7,7 +7,7 @@ from typing import Any
|
|
|
7
7
|
|
|
8
8
|
import pandas as pd
|
|
9
9
|
|
|
10
|
-
from table_stream import HashMapDict, ArrayList, File,
|
|
10
|
+
from table_stream import HashMapDict, ArrayList, File, TableMap, RowH
|
|
11
11
|
from cartas import TableTOI, HeaderTOI, TipoCarta, LocalEntregaCarta
|
|
12
12
|
|
|
13
13
|
|
|
@@ -43,7 +43,7 @@ class ResultStatus:
|
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
# ---------------------------------------------------------------------- normalização
|
|
46
|
-
_EMPTY = {"", "nan", "NaN", "None", "NaT",
|
|
46
|
+
_EMPTY = {"", "nan", "NaN", "None", "NaT", TableMap.NULL_STRING}
|
|
47
47
|
_DATE_FORMATS = (
|
|
48
48
|
"%d %m %Y", # DateValues.DATE_TOI (saída do relatório TOI)
|
|
49
49
|
"%d/%m/%Y",
|
|
@@ -70,11 +70,13 @@ def normalize_date(value: Any) -> str:
|
|
|
70
70
|
s = clean_text(value)
|
|
71
71
|
if not s:
|
|
72
72
|
raise ValueError("data de entrega vazia")
|
|
73
|
+
|
|
73
74
|
for fmt in _DATE_FORMATS:
|
|
74
75
|
try:
|
|
75
76
|
return datetime.strptime(s, fmt).strftime("%d/%m/%Y")
|
|
76
77
|
except ValueError:
|
|
77
78
|
continue
|
|
79
|
+
|
|
78
80
|
raise ValueError(f"data de entrega inválida: {s}")
|
|
79
81
|
|
|
80
82
|
|
|
@@ -104,8 +106,8 @@ class MapRows(HashMapDict[int, RowH[HeaderForms, Any]]):
|
|
|
104
106
|
self.update_status(idx, StatusForms.PENDING)
|
|
105
107
|
|
|
106
108
|
# ---- conversões
|
|
107
|
-
def to_table(self) ->
|
|
108
|
-
tb =
|
|
109
|
+
def to_table(self) -> TableMap[HeaderForms]:
|
|
110
|
+
tb = TableMap()
|
|
109
111
|
for idx in self.header():
|
|
110
112
|
tb.add_row(self.get_value(idx))
|
|
111
113
|
return tb
|
|
@@ -117,9 +119,11 @@ class MapRows(HashMapDict[int, RowH[HeaderForms, Any]]):
|
|
|
117
119
|
def to_view_data(self) -> pd.DataFrame:
|
|
118
120
|
"""DataFrame enxuto para exibir na tabela da UI."""
|
|
119
121
|
records = []
|
|
122
|
+
|
|
120
123
|
for idx in self.header():
|
|
121
124
|
r = self[idx]
|
|
122
125
|
path = clean_text(r.get(HeaderForms.FULL_PATH))
|
|
126
|
+
|
|
123
127
|
records.append({
|
|
124
128
|
"#": idx + 1,
|
|
125
129
|
"STATUS": str(r.get(HeaderForms.STATUS)),
|
|
@@ -131,12 +135,14 @@ class MapRows(HashMapDict[int, RowH[HeaderForms, Any]]):
|
|
|
131
135
|
"TIPO": r.get(HeaderForms.TIPO),
|
|
132
136
|
"ARQUIVO": os.path.basename(path) if path else "-",
|
|
133
137
|
})
|
|
138
|
+
|
|
134
139
|
return pd.DataFrame(records)
|
|
135
140
|
|
|
136
141
|
def save(self, file: File) -> None:
|
|
137
142
|
df = self.to_data()
|
|
138
143
|
if df is None:
|
|
139
144
|
return
|
|
145
|
+
|
|
140
146
|
df.to_excel(file.absolute(), index=False)
|
|
141
147
|
|
|
142
148
|
# ---- criação a partir da tabela TOI
|
|
@@ -165,8 +171,6 @@ class MapRows(HashMapDict[int, RowH[HeaderForms, Any]]):
|
|
|
165
171
|
|
|
166
172
|
@classmethod
|
|
167
173
|
def create_from_table(cls, tb: TableTOI) -> MapRows:
|
|
168
|
-
# NOTA: não usa tb.rows(): TableElements.rows() usa range(total-1)
|
|
169
|
-
# e descarta a ÚLTIMA linha da tabela.
|
|
170
174
|
mp = cls()
|
|
171
175
|
for n in range(tb.size()):
|
|
172
176
|
mp.set_value(n, cls.convert_row(tb.get_row_at(n)))
|
|
@@ -197,19 +197,29 @@ class ControllerForms(ChangeNotifier):
|
|
|
197
197
|
|
|
198
198
|
self.save_result(silent=True)
|
|
199
199
|
self.notify_listeners()
|
|
200
|
+
|
|
201
|
+
def get_dir_datetime(self) -> str:
|
|
202
|
+
t = datetime.now()
|
|
203
|
+
d = f"{t.year}-{t.month}-{t.day}"
|
|
204
|
+
return d
|
|
200
205
|
|
|
201
206
|
# ------------------------------------------------------------------ resultado
|
|
202
207
|
def save_result(self, *, silent: bool = False) -> None:
|
|
208
|
+
|
|
203
209
|
if self.map_rows.is_empty():
|
|
204
210
|
if not silent:
|
|
205
211
|
self.show_info("Nada para salvar.")
|
|
206
212
|
return
|
|
207
213
|
|
|
208
214
|
out = self.result_file
|
|
215
|
+
|
|
209
216
|
if out is None:
|
|
210
217
|
out_dir: Directory = self.get_config().value.work_dir.concat("Forms", True).concat("Resultados", True)
|
|
211
|
-
|
|
218
|
+
out_dir = out_dir.concat(self.get_dir_datetime(), True)
|
|
219
|
+
|
|
220
|
+
out = out_dir.join_file(f"LogForms-{datetime.now():%Y%m%d-%H%M%S}.xlsx")
|
|
212
221
|
self.result_file = out
|
|
222
|
+
|
|
213
223
|
try:
|
|
214
224
|
# grava em arquivo temporário e renomeia: nunca deixa um .xlsx corrompido/0 bytes
|
|
215
225
|
tmp = File(f"{out.absolute()}-tmp.xlsx")
|
|
@@ -127,14 +127,17 @@ class ModelForms(object):
|
|
|
127
127
|
|
|
128
128
|
# ------------------------------------------------------------------ execução
|
|
129
129
|
def start(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
130
|
+
self,
|
|
131
|
+
jobs: dict[int, FormsSubmission],
|
|
132
|
+
config: FormsConfig,
|
|
133
|
+
cb: FormsCallbacks,
|
|
134
|
+
) -> None:
|
|
135
|
+
|
|
135
136
|
if self.is_running():
|
|
136
137
|
raise RuntimeError("Já existe um lançamento em andamento")
|
|
138
|
+
|
|
137
139
|
self._stop.clear()
|
|
140
|
+
|
|
138
141
|
self._thread = threading.Thread(
|
|
139
142
|
target=self._worker, args=(jobs, config, cb), daemon=True, name="forms-worker",
|
|
140
143
|
)
|