IO4IT 4.0.30__tar.gz → 4.0.32__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 (117) hide show
  1. {io4it-4.0.30 → io4it-4.0.32}/PKG-INFO +1 -1
  2. {io4it-4.0.30 → io4it-4.0.32}/io4it.egg-info/PKG-INFO +1 -1
  3. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWDoclingToMarkdown.py +10 -53
  4. io4it-4.0.32/orangecontrib/IO4IT/widgets/OWMarkdownLoader.py +181 -0
  5. io4it-4.0.32/orangecontrib/IO4IT/widgets/designer/owmarkdownloader.ui +147 -0
  6. {io4it-4.0.30 → io4it-4.0.32}/setup.py +1 -1
  7. io4it-4.0.30/orangecontrib/IO4IT/widgets/OWMarkdownLoader.py +0 -131
  8. io4it-4.0.30/orangecontrib/IO4IT/widgets/designer/owmarkdownloader.ui +0 -111
  9. {io4it-4.0.30 → io4it-4.0.32}/io4it.egg-info/SOURCES.txt +0 -0
  10. {io4it-4.0.30 → io4it-4.0.32}/io4it.egg-info/dependency_links.txt +0 -0
  11. {io4it-4.0.30 → io4it-4.0.32}/io4it.egg-info/entry_points.txt +0 -0
  12. {io4it-4.0.30 → io4it-4.0.32}/io4it.egg-info/namespace_packages.txt +0 -0
  13. {io4it-4.0.30 → io4it-4.0.32}/io4it.egg-info/requires.txt +0 -0
  14. {io4it-4.0.30 → io4it-4.0.32}/io4it.egg-info/top_level.txt +0 -0
  15. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/__init__.py +0 -0
  16. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/ocr_function/__init__.py +0 -0
  17. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/ocr_function/word_converter.py +0 -0
  18. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/toolViews/designer/key_manager_ui.ui +0 -0
  19. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/toolViews/designer/link_workflow_manager_ui.ui +0 -0
  20. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/toolViews/key_manager_ui.py +0 -0
  21. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/toolViews/linkHTLMWorkflow_manager_ui.py +0 -0
  22. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/utils/__init__.py +0 -0
  23. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/utils/custom_api.py +0 -0
  24. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/utils/environment_collector.py +0 -0
  25. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/utils/file2images.py +0 -0
  26. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/utils/keys_manager.py +0 -0
  27. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/utils/mail.py +0 -0
  28. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/utils/pool_exec_utils.py +0 -0
  29. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/utils/pst_extractor/TigerODMPST.dll +0 -0
  30. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/utils/pst_extractor/__init__.py +0 -0
  31. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/utils/pst_extractor/export_pst.py +0 -0
  32. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/utils/pst_extractor/libpff.dll +0 -0
  33. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/utils/pst_extractor/z.dll +0 -0
  34. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/utils/secret_manager.py +0 -0
  35. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/utils/utils_md.py +0 -0
  36. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWChatGpt.py +0 -0
  37. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWCustomLLMApi.py +0 -0
  38. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWDeep_Search.py +0 -0
  39. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWExportMarkdown.py +0 -0
  40. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWExtractTablesDocxToXlsx.py +0 -0
  41. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWInboxMailMonitoring.py +0 -0
  42. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWJsonToDataTable.py +0 -0
  43. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWMD2HTML.py +0 -0
  44. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWMarkdownizer.py +0 -0
  45. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWOfficeNormalizer.py +0 -0
  46. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWPPTX2JPG.py +0 -0
  47. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWParserHTML.py +0 -0
  48. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWPdfType.py +0 -0
  49. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWPipAuditor.py +0 -0
  50. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWProcessPoolExecutor.py +0 -0
  51. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWS3Uploader.py +0 -0
  52. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWS3downloader.py +0 -0
  53. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWS3list.py +0 -0
  54. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWWebSearch.py +0 -0
  55. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWXLSX_insert.py +0 -0
  56. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWmailLoader.py +0 -0
  57. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWmailSender.py +0 -0
  58. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/OWwordpdf2docx.py +0 -0
  59. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/__init__.py +0 -0
  60. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/__init__.py +0 -0
  61. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/nogui.ui +0 -0
  62. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/ow_extract_tables_docx_to_xlsx.ui +0 -0
  63. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/ow_file_ext_selector.ui +0 -0
  64. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/ow_json_to_data_table.ui +0 -0
  65. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owchatgpt.ui +0 -0
  66. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owcustomllmapi.ui +0 -0
  67. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owdeepsearch.ui +0 -0
  68. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owdoclingtomarkdown.ui +0 -0
  69. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owexportmarkdown.ui +0 -0
  70. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owfile2images.ui +0 -0
  71. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owinboxmailmonitoring.ui +0 -0
  72. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owinsertdatatoexcel.ui +0 -0
  73. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owmailloader.ui +0 -0
  74. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owmailsender.ui +0 -0
  75. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owmarkdownizer.ui +0 -0
  76. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owmd2html.ui +0 -0
  77. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owofficenormalizer.ui +0 -0
  78. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owparserhtml.ui +0 -0
  79. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owpdftype.ui +0 -0
  80. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owpipauditor.ui +0 -0
  81. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owprocesspoolexecutor.ui +0 -0
  82. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owspeechtotext.ui +0 -0
  83. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owvisualizationer.ui +0 -0
  84. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/owwebsearch.ui +0 -0
  85. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/designer/wordpdf2docx.ui +0 -0
  86. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/__init__.py +0 -0
  87. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/chatgpt.png +0 -0
  88. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/check_pdf.png +0 -0
  89. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/deepsearch.svg +0 -0
  90. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/dep_md_old.png +0 -0
  91. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/download.png +0 -0
  92. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/export_md.png +0 -0
  93. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/extract_table.png +0 -0
  94. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/file2images.png +0 -0
  95. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/file_extensor.png +0 -0
  96. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/html.png +0 -0
  97. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/json-file.png +0 -0
  98. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/list_aws.png +0 -0
  99. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/load_md.png +0 -0
  100. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/mail_loader.png +0 -0
  101. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/mail_writer.png +0 -0
  102. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/md.png +0 -0
  103. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/monitor-email.svg +0 -0
  104. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/office_normalizer.png +0 -0
  105. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/owcustomllmapi.svg +0 -0
  106. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/owmd2html.svg +0 -0
  107. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/pip_auditor.png +0 -0
  108. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/process_pool_executor.png +0 -0
  109. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/speech_to_text.png +0 -0
  110. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/upload.png +0 -0
  111. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/visualizationer.png +0 -0
  112. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/websearch.png +0 -0
  113. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/wordpdf2docx.png +0 -0
  114. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons/xlsx_insert.png +0 -0
  115. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/IO4IT/widgets/icons_dev/__init__.py +0 -0
  116. {io4it-4.0.30 → io4it-4.0.32}/orangecontrib/__init__.py +0 -0
  117. {io4it-4.0.30 → io4it-4.0.32}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: io4it
3
- Version: 4.0.30
3
+ Version: 4.0.32
4
4
  Home-page:
5
5
  Author:
6
6
  Author-email:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: io4it
3
- Version: 4.0.30
3
+ Version: 4.0.32
4
4
  Home-page:
5
5
  Author:
6
6
  Author-email:
@@ -1,4 +1,4 @@
1
- import os, time, sys, re, math
1
+ import os, time, sys, re
2
2
  from pathlib import Path
3
3
  from concurrent.futures import as_completed
4
4
 
@@ -32,14 +32,14 @@ except ImportError:
32
32
  if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
33
33
  from Orange.widgets.orangecontrib.AAIT.utils.thread_management import Thread
34
34
  from Orange.widgets.orangecontrib.AAIT.utils.import_uic import uic
35
- from Orange.widgets.orangecontrib.AAIT.utils.local_store_sync import get_path_or_retrieve, file_mapping
36
- from Orange.widgets.orangecontrib.AAIT.utils.MetManagement import GetFromRemote, get_local_store_path
35
+ from Orange.widgets.orangecontrib.AAIT.utils.local_store_sync import get_path_or_retrieve
36
+ from Orange.widgets.orangecontrib.AAIT.utils.MetManagement import GetFromRemote
37
37
  from Orange.widgets.orangecontrib.AAIT.utils import SimpleDialogQt
38
38
  else:
39
39
  from orangecontrib.AAIT.utils.thread_management import Thread
40
40
  from orangecontrib.AAIT.utils.import_uic import uic
41
- from orangecontrib.AAIT.utils.local_store_sync import get_path_or_retrieve, file_mapping
42
- from orangecontrib.AAIT.utils.MetManagement import GetFromRemote, get_local_store_path
41
+ from orangecontrib.AAIT.utils.local_store_sync import get_path_or_retrieve
42
+ from orangecontrib.AAIT.utils.MetManagement import GetFromRemote
43
43
  from orangecontrib.AAIT.utils import SimpleDialogQt
44
44
 
45
45
  # Clé AAIT store des modèles Docling (layout, tableformer, RapidOcr)
@@ -183,26 +183,6 @@ def _docling_models_complete(artifacts_path: str) -> bool:
183
183
  return all(k in ocr for k in ("det_model_path", "cls_model_path", "rec_model_path"))
184
184
 
185
185
 
186
- def _download_docling_models_hf(output_dir: str):
187
- """Télécharge depuis HuggingFace/ModelScope les modèles utilisés par le widget
188
- (layout, tableformer, RapidOCR torch) directement dans output_dir (AAIT store).
189
- Docling choisit les poids RapidOCR adaptés à la version de rapidocr installée."""
190
- from docling.utils.model_downloader import download_models
191
- try:
192
- from docling.models.stages.ocr.rapid_ocr_model import _RAPIDOCR_DEFAULT_LANGUAGE as lang
193
- except ImportError:
194
- lang = "ch"
195
- download_models(
196
- Path(output_dir),
197
- with_layout=True,
198
- with_tableformer=True,
199
- with_code_formula=False,
200
- with_picture_classifier=False,
201
- with_rapidocr=True,
202
- rapidocr_models=[f"torch:{lang}"],
203
- )
204
-
205
-
206
186
  def _params_from_stem(stem: str, task: str, version_enum, type_enum) -> dict:
207
187
  """Paramètres RapidOCR cohérents avec le fichier choisi (version, taille).
208
188
  Utilisés notamment pour retrouver le dictionnaire de caractères de la reconnaissance."""
@@ -397,8 +377,6 @@ class OWDoclingToMarkdown(widget.OWWidget):
397
377
  self.processed_statuses = {} # Dictionary to accumulate statuses for each file
398
378
  # Chemin des modèles Docling dans l'AAIT store ("" = indisponibles : PDF non convertis)
399
379
  self.artifacts_path = ""
400
- # True : modèles à télécharger depuis HuggingFace dans artifacts_path (fait dans le thread)
401
- self.hf_download_pending = False
402
380
 
403
381
  self.setFixedWidth(470)
404
382
  self.setFixedHeight(300)
@@ -494,12 +472,12 @@ class OWDoclingToMarkdown(widget.OWWidget):
494
472
  self.thread.start()
495
473
 
496
474
  def _resolve_docling_models(self):
497
- """Cherche les modèles Docling dans l'AAIT store, propose le téléchargement sinon :
498
- 1) depuis le remote AAIT store, 2) à défaut depuis HuggingFace, dans l'AAIT store.
475
+ """Cherche les modèles Docling dans l'AAIT store, propose le téléchargement
476
+ depuis le remote AAIT store sinon. Aucune autre source : à défaut, les PDF
477
+ ne sont pas convertis.
499
478
  Appelé dans le thread GUI (boîtes de dialogue). Revérifié à chaque exécution :
500
479
  les modèles ont pu être supprimés depuis la dernière résolution.
501
480
  """
502
- self.hf_download_pending = False
503
481
  if _docling_models_complete(self.artifacts_path):
504
482
  return
505
483
  self.artifacts_path = ""
@@ -517,19 +495,9 @@ class OWDoclingToMarkdown(widget.OWWidget):
517
495
  SimpleDialogQt.BoxError("Unable to get the Model." + (f"\n{incompat}" if incompat else ""))
518
496
  raise ValueError(f"Docling models still incomplete in: {path} {incompat}")
519
497
  self.artifacts_path = path
520
- return
521
498
  except Exception as e:
522
499
  print(f"[Docling] modèles AAIT store indisponibles : {e}")
523
-
524
- # Repli : téléchargement HuggingFace, mais dans l'AAIT store (fonctionne ensuite hors ligne)
525
- store_path = os.path.join(get_local_store_path(), file_mapping[DOCLING_MODELS_KEY]).replace("\\", "/")
526
- if SimpleDialogQt.BoxYesNo("Docling models are not available from AAIT store.\n"
527
- "Do you want to download them from HuggingFace (~700 MB, internet required) "
528
- f"into your AAIT store?\n{store_path}"):
529
- self.artifacts_path = store_path
530
- self.hf_download_pending = True
531
- else:
532
- self.warning("Modèles Docling indisponibles : les PDF ne seront pas convertis.")
500
+ self.warning("Modèles Docling indisponibles (AAIT store) : les PDF ne seront pas convertis.")
533
501
 
534
502
  def update_status_output(self):
535
503
  """Helper function to create and send the status table."""
@@ -556,17 +524,6 @@ class OWDoclingToMarkdown(widget.OWWidget):
556
524
  artifacts_path = self.artifacts_path
557
525
  models_error = "modèles Docling indisponibles (AAIT store)"
558
526
 
559
- if pdfs and self.hf_download_pending:
560
- self.hf_download_pending = False
561
- for path_str in pdfs:
562
- self.status_update_signal.emit([path_str, "in_progress", "téléchargement des modèles Docling (HuggingFace)..."])
563
- try:
564
- _download_docling_models_hf(artifacts_path)
565
- except Exception as e:
566
- models_error = f"téléchargement HuggingFace des modèles Docling échoué : {type(e).__name__}: {e}"
567
- if not _docling_models_complete(artifacts_path):
568
- artifacts_path = ""
569
-
570
527
  # Gère le chemin du fichier Excel
571
528
  base_name = "conversion_results" # Nom de base pour le fichier Excel
572
529
  # Définir le chemin du dossier de sortie de Docling
@@ -676,4 +633,4 @@ if __name__ == "__main__":
676
633
  if hasattr(app, "exec"):
677
634
  app.exec()
678
635
  else:
679
- app.exec_()
636
+ app.exec_()
@@ -0,0 +1,181 @@
1
+ import os, sys
2
+ from pathlib import Path
3
+ import numpy as np
4
+ import re
5
+ import Orange.data
6
+ from AnyQt.QtWidgets import QApplication, QCheckBox, QPushButton
7
+ from Orange.data import StringVariable, Table, Domain
8
+ from Orange.widgets.utils.signals import Input, Output
9
+ from Orange.widgets.settings import Setting
10
+ from AnyQt.QtCore import QTimer
11
+
12
+ if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
13
+ from Orange.widgets.orangecontrib.AAIT.utils import base_widget, help_management
14
+ from Orange.widgets.orangecontrib.AAIT.utils.initialize_from_ini import apply_modification_from_python_file
15
+ from Orange.widgets.orangecontrib.IO4IT.utils import utils_md
16
+ else:
17
+ from orangecontrib.AAIT.utils import base_widget, help_management
18
+ from orangecontrib.AAIT.utils.initialize_from_ini import apply_modification_from_python_file
19
+ from orangecontrib.IO4IT.utils import utils_md
20
+ from orangecontrib.AAIT.utils.import_uic import uic
21
+
22
+
23
+ @apply_modification_from_python_file(filepath_original_widget=__file__)
24
+ class OWMarkdownLoader(base_widget.BaseListWidget):
25
+ name = "Markdown Loader"
26
+ description = "Load Markdown files from a folder (recursively) or directly from specific file paths."
27
+ icon = "icons/load_md.png"
28
+ if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
29
+ icon = "icons_dev/load_md.png"
30
+ gui = os.path.join(os.path.dirname(os.path.abspath(__file__)), "designer/owmarkdownloader.ui")
31
+ want_control_area = False
32
+ priority = 1001
33
+
34
+ selected_column_name = Setting("input_dir")
35
+ recursive = Setting(False)
36
+ class Inputs:
37
+ data = Input("Data", Orange.data.Table)
38
+
39
+ class Outputs:
40
+ md_files = Output("Markdown Files", Orange.data.Table) # -> (file_path, content)
41
+ data = Output("Data", Orange.data.Table) # passthrough de l'entrée
42
+
43
+ @Inputs.data
44
+ def set_path_table(self, in_data):
45
+ self.data = in_data
46
+
47
+ # Always pass through the input data
48
+ self.Outputs.data.send(in_data)
49
+
50
+ if in_data is None:
51
+ self.Outputs.md_files.send(self._empty_md_table())
52
+ return
53
+
54
+ if self.data:
55
+ # Remplissage du selecteur de colonnes (issu de BaseListWidget)
56
+ self.var_selector.add_variables(self.data.domain)
57
+ self.var_selector.select_variable_by_name(self.selected_column_name)
58
+
59
+ self.run()
60
+
61
+ def __init__(self):
62
+ super().__init__()
63
+ # Qt Management
64
+ self.setFixedWidth(500)
65
+ self.setFixedHeight(400)
66
+
67
+ self.data = None
68
+ self.autorun = True
69
+
70
+ # Checkbox Récursif
71
+ self.checkBoxRecursive = self.findChild(QCheckBox, 'checkBoxRecursive')
72
+ self.checkBoxRecursive.setChecked(self.recursive)
73
+ self.checkBoxRecursive.stateChanged.connect(self._on_recursive_toggled)
74
+
75
+ # Run Button
76
+ self.pushButton_run = self.findChild(QPushButton, 'pushButton_send')
77
+ self.pushButton_run.clicked.connect(self.run)
78
+
79
+ QTimer.singleShot(0, lambda: help_management.override_help_action(self))
80
+ self.post_initialized()
81
+
82
+ def _on_recursive_toggled(self, state):
83
+ self.recursive = self.checkBoxRecursive.isChecked()
84
+ if self.data is not None:
85
+ self.run()
86
+
87
+ def update_parameters(self):
88
+ if self.data is not None:
89
+ self.run()
90
+
91
+ def _empty_md_table(self) -> Table:
92
+ domain = Domain([], metas=[StringVariable("file_path"), StringVariable("content")])
93
+ X = np.empty((0, 0))
94
+ metas = np.empty((0, 2), dtype=object)
95
+ return Table.from_numpy(domain, X, metas=metas)
96
+
97
+ def run(self):
98
+ self.error("")
99
+ self.warning("")
100
+
101
+ if self.data is None:
102
+ self.Outputs.md_files.send(self._empty_md_table())
103
+ return
104
+
105
+ if not self.selected_column_name in self.data.domain:
106
+ self.warning(f'Previously selected column "{self.selected_column_name}" does not exist in your data.')
107
+ self.Outputs.md_files.send(self._empty_md_table())
108
+ return
109
+
110
+ # Récupération sécurisée des chemins depuis la colonne sélectionnée
111
+ try:
112
+ if hasattr(self.data, "get_column"):
113
+ input_paths = self.data.get_column(self.selected_column_name)
114
+ else:
115
+ # Fallback au cas où get_column n'existe pas
116
+ col_idx = self.data.domain.index(self.selected_column_name)
117
+ input_paths = [row[col_idx].value for row in self.data]
118
+ except Exception as e:
119
+ self.error(f"Error reading column data: {e}")
120
+ return
121
+
122
+ md_rows = []
123
+ seen_paths = set()
124
+
125
+ for p_val in input_paths:
126
+ if not p_val:
127
+ continue
128
+
129
+ p_str = str(p_val)
130
+ if not os.path.exists(p_str):
131
+ continue
132
+
133
+ p = Path(p_str)
134
+
135
+ # CAS 1 : C'est un fichier direct
136
+ if p.is_file():
137
+ if p.suffix.lower() == ".md" and p not in seen_paths:
138
+ seen_paths.add(p)
139
+ try:
140
+ md_rows.append([str(p), utils_md.try_read_text(p)])
141
+ except Exception:
142
+ md_rows.append([str(p), ""])
143
+
144
+ # CAS 2 : C'est un répertoire
145
+ elif p.is_dir():
146
+ patterns = ["*.md"]
147
+ found_paths = []
148
+ for patt in patterns:
149
+ if self.recursive:
150
+ found_paths.extend(p.rglob(patt))
151
+ else:
152
+ found_paths.extend(p.glob(patt))
153
+
154
+ for fp in found_paths:
155
+ if fp not in seen_paths and fp.is_file():
156
+ seen_paths.add(fp)
157
+ try:
158
+ md_rows.append([str(fp), utils_md.try_read_text(fp)])
159
+ except Exception:
160
+ md_rows.append([str(fp), ""])
161
+
162
+ # Formatage des données de sortie
163
+ domain = Domain([], metas=[StringVariable("file_path"), StringVariable("content")])
164
+ X = np.empty((len(md_rows), 0))
165
+ metas = np.array(md_rows, dtype=object) if md_rows else np.empty((0, 2), dtype=object)
166
+ md_table = Table.from_numpy(domain, X, metas=metas)
167
+
168
+ self.Outputs.md_files.send(md_table)
169
+
170
+ def post_initialized(self):
171
+ pass
172
+
173
+
174
+ if __name__ == "__main__":
175
+ app = QApplication(sys.argv)
176
+ my_widget = OWMarkdownLoader()
177
+ my_widget.show()
178
+ if hasattr(app, "exec"):
179
+ app.exec()
180
+ else:
181
+ app.exec_()
@@ -0,0 +1,147 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ui version="4.0">
3
+ <class>Form</class>
4
+ <widget class="QWidget" name="Form">
5
+ <property name="geometry">
6
+ <rect>
7
+ <x>0</x>
8
+ <y>0</y>
9
+ <width>478</width>
10
+ <height>400</height>
11
+ </rect>
12
+ </property>
13
+ <property name="windowTitle">
14
+ <string>Markdown Loader</string>
15
+ </property>
16
+ <widget class="QGroupBox" name="groupBox">
17
+ <property name="geometry">
18
+ <rect>
19
+ <x>19</x>
20
+ <y>10</y>
21
+ <width>441</width>
22
+ <height>121</height>
23
+ </rect>
24
+ </property>
25
+ <property name="title">
26
+ <string>Parameters</string>
27
+ </property>
28
+ <widget class="QLabel" name="Description">
29
+ <property name="geometry">
30
+ <rect>
31
+ <x>10</x>
32
+ <y>20</y>
33
+ <width>421</width>
34
+ <height>61</height>
35
+ </rect>
36
+ </property>
37
+ <property name="text">
38
+ <string>This widget loads markdown from paths. If a path is a file, it loads it. If it's a folder, it searches for markdown files inside.</string>
39
+ </property>
40
+ <property name="textFormat">
41
+ <enum>Qt::AutoText</enum>
42
+ </property>
43
+ <property name="alignment">
44
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
45
+ </property>
46
+ <property name="wordWrap">
47
+ <bool>true</bool>
48
+ </property>
49
+ </widget>
50
+ <widget class="QCheckBox" name="checkBoxRecursive">
51
+ <property name="geometry">
52
+ <rect>
53
+ <x>10</x>
54
+ <y>85</y>
55
+ <width>421</width>
56
+ <height>21</height>
57
+ </rect>
58
+ </property>
59
+ <property name="text">
60
+ <string>Recursive search (if path is a directory)</string>
61
+ </property>
62
+ </widget>
63
+ </widget>
64
+ <widget class="QGroupBox" name="groupBox_3">
65
+ <property name="geometry">
66
+ <rect>
67
+ <x>20</x>
68
+ <y>140</y>
69
+ <width>441</width>
70
+ <height>161</height>
71
+ </rect>
72
+ </property>
73
+ <property name="title">
74
+ <string>Column selection</string>
75
+ </property>
76
+ <widget class="QLabel" name="Description_4">
77
+ <property name="geometry">
78
+ <rect>
79
+ <x>10</x>
80
+ <y>30</y>
81
+ <width>411</width>
82
+ <height>61</height>
83
+ </rect>
84
+ </property>
85
+ <property name="text">
86
+ <string/>
87
+ </property>
88
+ <property name="textFormat">
89
+ <enum>Qt::AutoText</enum>
90
+ </property>
91
+ <property name="alignment">
92
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
93
+ </property>
94
+ <property name="wordWrap">
95
+ <bool>true</bool>
96
+ </property>
97
+ </widget>
98
+ <widget class="QWidget" name="placeholder" native="true">
99
+ <property name="enabled">
100
+ <bool>true</bool>
101
+ </property>
102
+ <property name="geometry">
103
+ <rect>
104
+ <x>0</x>
105
+ <y>20</y>
106
+ <width>431</width>
107
+ <height>141</height>
108
+ </rect>
109
+ </property>
110
+ </widget>
111
+ </widget>
112
+ <widget class="QPushButton" name="pushButton_send">
113
+ <property name="enabled">
114
+ <bool>true</bool>
115
+ </property>
116
+ <property name="geometry">
117
+ <rect>
118
+ <x>160</x>
119
+ <y>330</y>
120
+ <width>301</width>
121
+ <height>31</height>
122
+ </rect>
123
+ </property>
124
+ <property name="text">
125
+ <string>Run</string>
126
+ </property>
127
+ </widget>
128
+ <widget class="QCheckBox" name="checkBox_send">
129
+ <property name="enabled">
130
+ <bool>false</bool>
131
+ </property>
132
+ <property name="geometry">
133
+ <rect>
134
+ <x>20</x>
135
+ <y>340</y>
136
+ <width>131</width>
137
+ <height>16</height>
138
+ </rect>
139
+ </property>
140
+ <property name="text">
141
+ <string>Auto send data</string>
142
+ </property>
143
+ </widget>
144
+ </widget>
145
+ <resources/>
146
+ <connections/>
147
+ </ui>
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  # Configuration
4
4
  NAME = "io4it"
5
- VERSION = "4.0.30"
5
+ VERSION = "4.0.32"
6
6
 
7
7
  INSTALL_REQUIRES = [
8
8
  "torchvision",
@@ -1,131 +0,0 @@
1
- import os, sys
2
- from pathlib import Path
3
- import numpy as np
4
- import re
5
- from Orange.widgets import widget
6
- from Orange.widgets.utils.signals import Input, Output
7
- from Orange.data import Domain, StringVariable, Table
8
- from AnyQt.QtWidgets import QCheckBox, QApplication
9
- from Orange.widgets.settings import Setting
10
-
11
-
12
- if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
13
- from Orange.widgets.orangecontrib.AAIT.utils.import_uic import uic
14
- from Orange.widgets.orangecontrib.IO4IT.utils import utils_md
15
- else:
16
- from orangecontrib.IO4IT.utils import utils_md
17
- from orangecontrib.AAIT.utils.import_uic import uic
18
-
19
-
20
- class OWMarkdownLoader(widget.OWWidget):
21
- name = "Markdown Loader"
22
- description = "Load all Markdown files from a folder (recursively)."
23
- icon = "icons/load_md.png"
24
- if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
25
- icon = "icons_dev/load_md.png"
26
- gui = os.path.join(os.path.dirname(os.path.abspath(__file__)), "designer/owmarkdownloader.ui")
27
- want_control_area = False
28
- priority = 1001
29
- recursive = Setting(False)
30
- class Inputs:
31
- data = Input("Data", Table)
32
-
33
- class Outputs:
34
- md_files = Output("Markdown Files", Table) # -> (file_path, content)
35
- data = Output("Data", Table) # passthrough de l'entrée
36
-
37
- def __init__(self):
38
- super().__init__()
39
-
40
- self.in_data = None
41
- self.input_dir = None
42
- uic.loadUi(self.gui, self)
43
-
44
-
45
- self.checkBoxRecursive = self.findChild(QCheckBox, 'checkBoxRecursive')
46
- # These lines MUST be after super().__init__()
47
- if self.recursive:
48
- self.checkBoxRecursive.setChecked(True)
49
- else:
50
- self.checkBoxRecursive.setChecked(False)
51
- self.recursive = self.checkBoxRecursive.isChecked()
52
- self.checkBoxRecursive.stateChanged.connect(self._on_recursive_toggled)
53
-
54
- self.warning("")
55
-
56
- def _on_recursive_toggled(self, _state):
57
- self.recursive = self.checkBoxRecursive.isChecked()
58
- # If a directory is already set, re-run the production
59
- if self.input_dir:
60
- self._produce()
61
-
62
- @Inputs.data
63
- def set_data(self, in_data: Table | None):
64
- self.in_data = in_data
65
- self.warning("")
66
-
67
- # Always pass through the input data
68
- self.Outputs.data.send(in_data)
69
-
70
- if not in_data:
71
- # If no input data, send an empty table
72
- self.Outputs.md_files.send(self._empty_md_table())
73
- self.Description.setText(
74
- "This widget loads Markdown files from a folder. The path must be in a column named 'input_dir'.")
75
- return
76
-
77
- # Look for the 'input_dir' column and get the first folder
78
- try:
79
- input_dir_column = in_data.domain["input_dir"]
80
- self.input_dir = str(in_data[0, input_dir_column].value)
81
- except (KeyError, IndexError, AttributeError):
82
- self.warning('"input_dir" (Text) is required in the input data.')
83
- self.Outputs.md_files.send(self._empty_md_table())
84
- self.Description.setText("Error: 'input_dir' (Text) column not found or is empty.")
85
- return
86
-
87
- self.Description.setText(f"Dossier : {self.input_dir}")
88
- self._produce()
89
-
90
- def _empty_md_table(self) -> Table:
91
- domain = Domain([], metas=[StringVariable("file_path"), StringVariable("content")])
92
- X = np.empty((0, 0))
93
- metas = np.empty((0, 2), dtype=object)
94
- return Table.from_numpy(domain, X, metas=metas)
95
-
96
- def _produce(self):
97
- if not self.input_dir or not os.path.isdir(self.input_dir):
98
- self.warning(f"Invalid directory path: '{self.input_dir}'")
99
- self.Outputs.md_files.send(self._empty_md_table())
100
- return
101
- base = Path(self.input_dir)
102
- patterns = ["*.md"]
103
- paths = []
104
-
105
- for patt in patterns:
106
- if self.recursive:
107
- paths.extend(base.rglob(patt))
108
- else:
109
- paths.extend(base.glob(patt))
110
-
111
- md_rows = []
112
- for p in sorted(set(paths)):
113
- try:
114
- md_rows.append([str(p), utils_md.try_read_text(p)])
115
- except Exception:
116
- md_rows.append([str(p), ""])
117
- domain = Domain([], metas=[StringVariable("file_path"), StringVariable("content")])
118
- X = np.empty((len(md_rows), 0))
119
- metas = np.array(md_rows, dtype=object) if md_rows else np.empty((0, 2), dtype=object)
120
- md_table = Table.from_numpy(domain, X, metas=metas)
121
-
122
- self.Outputs.md_files.send(md_table)
123
-
124
- if __name__ == "__main__":
125
- app = QApplication(sys.argv)
126
- my_widget = OWMarkdownLoader()
127
- my_widget.show()
128
- if hasattr(app, "exec"):
129
- app.exec()
130
- else:
131
- app.exec_()
@@ -1,111 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <ui version="4.0">
3
- <class>Form</class>
4
- <widget class="QWidget" name="Form">
5
- <property name="geometry">
6
- <rect>
7
- <x>0</x>
8
- <y>0</y>
9
- <width>470</width>
10
- <height>311</height>
11
- </rect>
12
- </property>
13
- <property name="minimumSize">
14
- <size>
15
- <width>470</width>
16
- <height>311</height>
17
- </size>
18
- </property>
19
- <property name="maximumSize">
20
- <size>
21
- <width>470</width>
22
- <height>311</height>
23
- </size>
24
- </property>
25
- <property name="windowTitle">
26
- <string>Form</string>
27
- </property>
28
- <widget class="QGroupBox" name="groupBox">
29
- <property name="geometry">
30
- <rect>
31
- <x>10</x>
32
- <y>30</y>
33
- <width>441</width>
34
- <height>171</height>
35
- </rect>
36
- </property>
37
- <property name="title">
38
- <string>Parameters</string>
39
- </property>
40
- <widget class="QLabel" name="Description">
41
- <property name="geometry">
42
- <rect>
43
- <x>10</x>
44
- <y>20</y>
45
- <width>431</width>
46
- <height>71</height>
47
- </rect>
48
- </property>
49
- <property name="text">
50
- <string>This widget load markdown from a folder, path must be in a column 'input_dir'</string>
51
- </property>
52
- <property name="textFormat">
53
- <enum>Qt::AutoText</enum>
54
- </property>
55
- <property name="alignment">
56
- <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
57
- </property>
58
- <property name="wordWrap">
59
- <bool>true</bool>
60
- </property>
61
- </widget>
62
- <widget class="QCheckBox" name="checkBoxRecursive">
63
- <property name="geometry">
64
- <rect>
65
- <x>10</x>
66
- <y>110</y>
67
- <width>431</width>
68
- <height>21</height>
69
- </rect>
70
- </property>
71
- <property name="text">
72
- <string>Recursive search</string>
73
- </property>
74
- </widget>
75
- </widget>
76
- <widget class="QPushButton" name="pushButton_send">
77
- <property name="enabled">
78
- <bool>false</bool>
79
- </property>
80
- <property name="geometry">
81
- <rect>
82
- <x>150</x>
83
- <y>224</y>
84
- <width>301</width>
85
- <height>31</height>
86
- </rect>
87
- </property>
88
- <property name="text">
89
- <string>Run</string>
90
- </property>
91
- </widget>
92
- <widget class="QCheckBox" name="checkBox_send">
93
- <property name="enabled">
94
- <bool>false</bool>
95
- </property>
96
- <property name="geometry">
97
- <rect>
98
- <x>10</x>
99
- <y>230</y>
100
- <width>131</width>
101
- <height>16</height>
102
- </rect>
103
- </property>
104
- <property name="text">
105
- <string>Auto send data</string>
106
- </property>
107
- </widget>
108
- </widget>
109
- <resources/>
110
- <connections/>
111
- </ui>
File without changes
File without changes