io4it 2.0.0.3__tar.gz → 2.0.0.5__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.
- io4it-2.0.0.5/PKG-INFO +7 -0
- io4it-2.0.0.5/io4it.egg-info/PKG-INFO +7 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/io4it.egg-info/SOURCES.txt +0 -2
- io4it-2.0.0.5/io4it.egg-info/entry_points.txt +7 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/io4it.egg-info/requires.txt +1 -5
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/utils/mail.py +12 -28
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/utils/offuscation_basique.py +16 -123
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/OWChatGpt.py +1 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/OWDeep_Search.py +1 -0
- io4it-2.0.0.5/orangecontrib/IO4IT/widgets/OWExportMarkdown.py +216 -0
- io4it-2.0.0.5/orangecontrib/IO4IT/widgets/OWMarkdownizer.py +563 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/OWS3Uploader.py +1 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/OWS3downloader.py +1 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/OWS3list.py +1 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/OWSpeechToText.py +1 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/OWmailLoader.py +1 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/OWmailSender.py +1 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/OWwordpdf2docx.py +1 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/setup.py +9 -8
- io4it-2.0.0.3/PKG-INFO +0 -28
- io4it-2.0.0.3/io4it.egg-info/PKG-INFO +0 -28
- io4it-2.0.0.3/io4it.egg-info/entry_points.txt +0 -2
- io4it-2.0.0.3/orangecontrib/IO4IT/widgets/OWExportMarkdown.py +0 -192
- io4it-2.0.0.3/orangecontrib/IO4IT/widgets/OWMarkdownizer.py +0 -251
- io4it-2.0.0.3/orangecontrib/IO4IT/widgets/designer/owchatgpt.ui +0 -155
- io4it-2.0.0.3/orangecontrib/IO4IT/widgets/designer/owmarkdownizer.ui +0 -101
- {io4it-2.0.0.3 → io4it-2.0.0.5}/io4it.egg-info/dependency_links.txt +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/io4it.egg-info/namespace_packages.txt +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/io4it.egg-info/top_level.txt +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/__init__.py +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/ocr_function/__init__.py +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/ocr_function/word_converter.py +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/utils/__init__.py +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/__init__.py +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/designer/__init__.py +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/designer/chart.html +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/designer/nogui.ui +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/designer/ow_file_ext_selector.ui +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/designer/owdeepsearch.ui +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/designer/owexportmarkdown.ui +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/designer/owmailloader.ui +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/designer/owmailsender.ui +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/designer/owspeechtotext.ui +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/designer/owvisualizationer.ui +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/designer/wordpdf2docx.ui +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/icons/__init__.py +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/icons/chatgpt.png +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/icons/deepsearch.svg +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/icons/download.png +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/icons/export_md.png +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/icons/file_extensor.png +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/icons/list_aws.png +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/icons/mail_loader.png +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/icons/mail_writer.png +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/icons/md.png +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/icons/speech_to_text.png +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/icons/upload.png +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/icons/visualizationer.png +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/icons/wordpdf2docx.png +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/IO4IT/widgets/icons_dev/__init__.py +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/orangecontrib/__init__.py +0 -0
- {io4it-2.0.0.3 → io4it-2.0.0.5}/setup.cfg +0 -0
io4it-2.0.0.5/PKG-INFO
ADDED
|
@@ -30,12 +30,10 @@ orangecontrib/IO4IT/widgets/designer/__init__.py
|
|
|
30
30
|
orangecontrib/IO4IT/widgets/designer/chart.html
|
|
31
31
|
orangecontrib/IO4IT/widgets/designer/nogui.ui
|
|
32
32
|
orangecontrib/IO4IT/widgets/designer/ow_file_ext_selector.ui
|
|
33
|
-
orangecontrib/IO4IT/widgets/designer/owchatgpt.ui
|
|
34
33
|
orangecontrib/IO4IT/widgets/designer/owdeepsearch.ui
|
|
35
34
|
orangecontrib/IO4IT/widgets/designer/owexportmarkdown.ui
|
|
36
35
|
orangecontrib/IO4IT/widgets/designer/owmailloader.ui
|
|
37
36
|
orangecontrib/IO4IT/widgets/designer/owmailsender.ui
|
|
38
|
-
orangecontrib/IO4IT/widgets/designer/owmarkdownizer.ui
|
|
39
37
|
orangecontrib/IO4IT/widgets/designer/owspeechtotext.ui
|
|
40
38
|
orangecontrib/IO4IT/widgets/designer/owvisualizationer.ui
|
|
41
39
|
orangecontrib/IO4IT/widgets/designer/wordpdf2docx.ui
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
[orange.widgets]
|
|
2
|
+
AAIT - API = orangecontrib.API.widgets
|
|
3
|
+
AAIT - Algorithm = orangecontrib.ALGORITHM.widgets
|
|
4
|
+
AAIT - LLM INTEGRATION = orangecontrib.LLM_INTEGRATION.widgets
|
|
5
|
+
AAIT - Models = orangecontrib.LLM_MODELS.widgets
|
|
6
|
+
AAIT - Toolbox = orangecontrib.TOOLBOX.widgets
|
|
7
|
+
Advanced Artificial Intelligence Tools = orangecontrib.AAIT.widgets
|
|
@@ -4,21 +4,19 @@ import email
|
|
|
4
4
|
from email.header import decode_header
|
|
5
5
|
import time
|
|
6
6
|
import os
|
|
7
|
+
from bs4 import BeautifulSoup
|
|
7
8
|
from email import policy
|
|
8
9
|
from email.message import EmailMessage
|
|
9
10
|
import mimetypes
|
|
10
11
|
|
|
11
|
-
from exchangelib import Credentials, HTMLBody, Message, Mailbox
|
|
12
|
+
from exchangelib import Credentials, Account, DELEGATE, Configuration, HTMLBody, Message, Mailbox
|
|
12
13
|
from exchangelib.protocol import BaseProtocol, NoVerifyHTTPAdapter
|
|
13
14
|
from exchangelib import OAuth2Credentials, Identity, Configuration, Account, DELEGATE
|
|
14
|
-
|
|
15
|
+
from oauthlib.oauth2 import OAuth2Token
|
|
15
16
|
|
|
16
17
|
from bs4 import BeautifulSoup
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
##### please uncomment this line to ignore certificate checking (owa)
|
|
20
|
-
#BaseProtocol.HTTP_ADAPTER_CLS=NoVerifyHTTPAdapter
|
|
21
|
-
|
|
18
|
+
BaseProtocol.HTTP_ADAPTER_CLS=NoVerifyHTTPAdapter
|
|
19
|
+
import json
|
|
22
20
|
from msal import ConfidentialClientApplication
|
|
23
21
|
from oauthlib.oauth2 import OAuth2Token
|
|
24
22
|
|
|
@@ -664,27 +662,13 @@ def check_send_new_emails(offusc_conf_agent,type_co):
|
|
|
664
662
|
else:
|
|
665
663
|
print("type de co non valide")
|
|
666
664
|
|
|
667
|
-
def list_conf_files(type_co):
|
|
668
|
-
conf_files = []
|
|
669
|
-
if type_co is None or type_co == "":
|
|
670
|
-
return conf_files
|
|
671
|
-
dossier = MetManagement.get_secret_content_dir()
|
|
672
|
-
dossier = dossier + type_co
|
|
673
|
-
files = os.listdir(dossier)
|
|
674
|
-
for file in files:
|
|
675
|
-
if file.lower().endswith(".json"):
|
|
676
|
-
conf_files.append(file)
|
|
677
|
-
return conf_files
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
665
|
if __name__ == "__main__":
|
|
682
|
-
|
|
666
|
+
offusc_conf_agent=""
|
|
667
|
+
#type_co="IMAP4_SSL"
|
|
668
|
+
type_co="MICROSOFT_EXCHANGE_OAUTH2"
|
|
683
669
|
list_agent_email = []
|
|
684
|
-
offusc_conf_agents = list_conf_files(type_co)
|
|
685
670
|
while True:
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
time.sleep(1)
|
|
671
|
+
check_new_emails(offusc_conf_agent,type_co, list_agent_email)
|
|
672
|
+
time.sleep(1)
|
|
673
|
+
check_send_new_emails(offusc_conf_agent,type_co)
|
|
674
|
+
time.sleep(1)
|
|
@@ -2,9 +2,6 @@ import os
|
|
|
2
2
|
import json
|
|
3
3
|
import hashlib
|
|
4
4
|
import getpass
|
|
5
|
-
from cryptography.fernet import Fernet
|
|
6
|
-
import base64
|
|
7
|
-
|
|
8
5
|
|
|
9
6
|
if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
|
|
10
7
|
from Orange.widgets.orangecontrib.AAIT.utils import MetManagement
|
|
@@ -50,26 +47,12 @@ def get_keys_dir(type_key: str = "MICROSOFT_EXCHANGE_OAUTH2") -> str:
|
|
|
50
47
|
if os.path.basename(base) != "keys":
|
|
51
48
|
base = os.path.join(base, "keys")
|
|
52
49
|
dossier = os.path.normpath(os.path.join(base, type_key))
|
|
50
|
+
print("dossier", dossier)
|
|
53
51
|
os.makedirs(dossier, exist_ok=True)
|
|
54
52
|
return dossier
|
|
55
53
|
except Exception as e:
|
|
56
54
|
raise RuntimeError(f"Erreur création/récupération dossier : {e}")
|
|
57
55
|
|
|
58
|
-
def get_fernet_key() -> bytes:
|
|
59
|
-
"""
|
|
60
|
-
Dérive une clé Fernet (32 octets base64) à partir du nom d'utilisateur local.
|
|
61
|
-
"""
|
|
62
|
-
username = getpass.getuser().encode("utf-8")
|
|
63
|
-
digest = hashlib.sha256(username).digest()
|
|
64
|
-
return base64.urlsafe_b64encode(digest[:32]) # 32 bytes en base64
|
|
65
|
-
|
|
66
|
-
def encrypt_secure(data: str) -> str:
|
|
67
|
-
fernet = Fernet(get_fernet_key())
|
|
68
|
-
return fernet.encrypt(data.encode("utf-8")).decode("utf-8")
|
|
69
|
-
|
|
70
|
-
def decrypt_secure(data: str) -> str:
|
|
71
|
-
fernet = Fernet(get_fernet_key())
|
|
72
|
-
return fernet.decrypt(data.encode("utf-8")).decode("utf-8")
|
|
73
56
|
|
|
74
57
|
|
|
75
58
|
# GSTION IMAP
|
|
@@ -177,83 +160,6 @@ def enregistrer_config_owa(mail,alias,server,username,password,interval):
|
|
|
177
160
|
print(f"❌ Erreur lors de l'enregistrement : {e}")
|
|
178
161
|
return 1
|
|
179
162
|
|
|
180
|
-
def enregistrer_config_owa_secure(mail, alias, server, username, password, interval):
|
|
181
|
-
try:
|
|
182
|
-
dossier = get_keys_dir("MICROSOFT_EXCHANGE_OWA_SECURE")
|
|
183
|
-
os.makedirs(dossier, exist_ok=True)
|
|
184
|
-
|
|
185
|
-
mdp_chiffre = encrypt_secure(password)
|
|
186
|
-
|
|
187
|
-
nom_fichier = os.path.join(dossier, f"{alias.replace('@', '_at_')}.json")
|
|
188
|
-
|
|
189
|
-
contenu = {
|
|
190
|
-
"mail": mail,
|
|
191
|
-
"alias": alias,
|
|
192
|
-
"server": server,
|
|
193
|
-
"username": username,
|
|
194
|
-
"password_encrypted": mdp_chiffre,
|
|
195
|
-
"interval_second": interval
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
with open(nom_fichier, "w", encoding="utf-8") as f:
|
|
199
|
-
json.dump(contenu, f, indent=4)
|
|
200
|
-
|
|
201
|
-
print(f"✅ Fichier OWA sécurisé enregistré : {nom_fichier}")
|
|
202
|
-
return 0
|
|
203
|
-
|
|
204
|
-
except Exception as e:
|
|
205
|
-
print(f"❌ Erreur d'enregistrement sécurisé OWA : {e}")
|
|
206
|
-
return 1
|
|
207
|
-
|
|
208
|
-
def enregistrer_config_cli_owa_secure():
|
|
209
|
-
print("\n🔐 Écriture fichier OWA avec chiffrement sécurisé :")
|
|
210
|
-
mail = input("📧 Mail (nom@domain.com) : ").strip()
|
|
211
|
-
alias = input("📛 Alias (visible) : ").strip()
|
|
212
|
-
server = input("🌐 Server : ").strip()
|
|
213
|
-
username = input("👤 Username (domain\\user) : ").strip()
|
|
214
|
-
password = input("🔑 Password (non masqué) : ").strip()
|
|
215
|
-
interval = int(input("⏱️ Interval (secondes) : ").strip())
|
|
216
|
-
if alias == "''" or alias == "\"\"" or alias == "":
|
|
217
|
-
alias = mail
|
|
218
|
-
|
|
219
|
-
if 0 != enregistrer_config_owa_secure(mail, alias, server, username, password, interval):
|
|
220
|
-
print("❌ Erreur lors de enregistrer_config_owa_secure !")
|
|
221
|
-
|
|
222
|
-
def lecture_config_cli_owa_secure():
|
|
223
|
-
fichier = input("📄 Nom du fichier JSON (sans chemin) : ").strip()
|
|
224
|
-
cfg = lire_config_owa_secure(fichier)
|
|
225
|
-
|
|
226
|
-
if cfg is None:
|
|
227
|
-
print("❌ Erreur")
|
|
228
|
-
return
|
|
229
|
-
|
|
230
|
-
print(f"\n📧 mail : {cfg[0]}")
|
|
231
|
-
print(f"📛 alias : {cfg[1]}")
|
|
232
|
-
print(f"🌐 server : {cfg[2]}")
|
|
233
|
-
print(f"👤 username : {cfg[3]}")
|
|
234
|
-
print(f"🔑 password : {cfg[4]}")
|
|
235
|
-
print(f"⏱️ intervalle : {cfg[5]}s")
|
|
236
|
-
|
|
237
|
-
def lire_config_owa_secure(chemin_fichier):
|
|
238
|
-
try:
|
|
239
|
-
chemin_fichier = os.path.join(get_keys_dir("MICROSOFT_EXCHANGE_OWA_SECURE"), chemin_fichier)
|
|
240
|
-
with open(chemin_fichier, "r", encoding="utf-8") as f:
|
|
241
|
-
contenu = json.load(f)
|
|
242
|
-
|
|
243
|
-
mdp_dechiffre = decrypt_secure(contenu["password_encrypted"])
|
|
244
|
-
|
|
245
|
-
return [
|
|
246
|
-
contenu["mail"],
|
|
247
|
-
contenu["alias"],
|
|
248
|
-
contenu["server"],
|
|
249
|
-
contenu["username"],
|
|
250
|
-
mdp_dechiffre,
|
|
251
|
-
int(contenu["interval_second"])
|
|
252
|
-
]
|
|
253
|
-
|
|
254
|
-
except Exception as e:
|
|
255
|
-
print(f"❌ Erreur de lecture sécurisée OWA : {e}")
|
|
256
|
-
return None
|
|
257
163
|
|
|
258
164
|
|
|
259
165
|
# Fonction pour lire le fichier de configuration et déchiffrer le mot de passe
|
|
@@ -451,28 +357,21 @@ def lire_config_api(service_name):
|
|
|
451
357
|
def enregistrer_config_cli_api():
|
|
452
358
|
print("\n📝 Écriture d’une clé API :")
|
|
453
359
|
service = input("🔖 Nom du service : ").strip()
|
|
454
|
-
api_key =
|
|
360
|
+
api_key = getpass.getpass("🔑 Clé API : ").strip()
|
|
455
361
|
desc = input("✏️ Description : ").strip()
|
|
456
362
|
if 0 != enregistrer_config_api(service, api_key, desc):
|
|
457
363
|
print("erreur!")
|
|
458
364
|
|
|
459
|
-
def lire_config_cli_api(
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
print(f"
|
|
469
|
-
if cfg['description']:
|
|
470
|
-
print(f"📝 description : {cfg['description']}")
|
|
471
|
-
return cfg['api_key']
|
|
472
|
-
except Exception as e:
|
|
473
|
-
print(f"❌ Erreur lors de la lecture : {e}")
|
|
474
|
-
return None
|
|
475
|
-
|
|
365
|
+
def lire_config_cli_api():
|
|
366
|
+
service = input("🔖 Nom du service : ").strip()
|
|
367
|
+
cfg = lire_config_api(service)
|
|
368
|
+
if cfg is None:
|
|
369
|
+
print("erreur")
|
|
370
|
+
return
|
|
371
|
+
print(f"\n📄 service : {cfg['service']}")
|
|
372
|
+
print(f"🔑 clé API : {cfg['api_key']}")
|
|
373
|
+
if cfg['description']:
|
|
374
|
+
print(f"📝 description : {cfg['description']}")
|
|
476
375
|
|
|
477
376
|
|
|
478
377
|
# Gestion d’éléments de nxp (DOSSIER_NODE_ID, SERVEUR, USERNAME, PASSWORD) (HARD dossier aait_store/keys)
|
|
@@ -559,6 +458,8 @@ def lire_config_cli_nxp():
|
|
|
559
458
|
print(f"📝 description : {cfg['description']}")
|
|
560
459
|
|
|
561
460
|
|
|
461
|
+
|
|
462
|
+
|
|
562
463
|
if __name__ == "__main__":
|
|
563
464
|
print("1) ecrire fichier IMAP4_SSL")
|
|
564
465
|
print("2) dechiffer fichier IMAP4_SSL")
|
|
@@ -570,10 +471,7 @@ if __name__ == "__main__":
|
|
|
570
471
|
print("8) Déchiffrer fichier Microsoft Exchange (OWA)")
|
|
571
472
|
print("9) Écrire fichier Microsoft Exchange (OAuth2)")
|
|
572
473
|
print("10) Déchiffrer fichier Microsoft Exchange (OAuth2)")
|
|
573
|
-
|
|
574
|
-
print("12) Déchiffrer fichier Microsoft Exchange (OWA) [SECURE]")
|
|
575
|
-
|
|
576
|
-
choix = input("👉 Que faire ? [1-12] : ").strip()
|
|
474
|
+
choix = input("👉 Que faire ? [1-10] : ").strip()
|
|
577
475
|
|
|
578
476
|
if choix == "1":
|
|
579
477
|
enregistrer_config_cli_imap4_ssl()
|
|
@@ -594,12 +492,7 @@ if __name__ == "__main__":
|
|
|
594
492
|
elif choix=="9":
|
|
595
493
|
enregistrer_config_cli_oauth2()
|
|
596
494
|
elif choix=="10":
|
|
597
|
-
|
|
598
|
-
elif choix == "11":
|
|
599
|
-
enregistrer_config_cli_owa_secure()
|
|
600
|
-
elif choix == "12":
|
|
601
|
-
lecture_config_cli_owa_secure()
|
|
602
|
-
|
|
495
|
+
lecture_config_cli_oauth2()
|
|
603
496
|
|
|
604
497
|
else:
|
|
605
498
|
print("❌ Choix invalide. Réessayez.\n")
|
|
@@ -30,6 +30,7 @@ class ChatGpt(OWWidget):
|
|
|
30
30
|
model = Setting("gpt-4o")
|
|
31
31
|
gui = os.path.join(os.path.dirname(os.path.abspath(__file__)), "designer/owchatgpt.ui")
|
|
32
32
|
want_control_area = False
|
|
33
|
+
category = "AAIT - AAIT - LLM INTEGRATION"
|
|
33
34
|
|
|
34
35
|
class Inputs:
|
|
35
36
|
data = Input("Data", Orange.data.Table)
|
|
@@ -27,6 +27,7 @@ else:
|
|
|
27
27
|
class OWDeep_Search(widget.OWWidget):
|
|
28
28
|
name = "Deep Search"
|
|
29
29
|
description = "Generate a response to a column 'prompt' with a LLM"
|
|
30
|
+
category = "AAIT - AAIT - LLM INTEGRATION"
|
|
30
31
|
icon = "icons/deepsearch.svg"
|
|
31
32
|
if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
|
|
32
33
|
icon = "icons_dev/owqueryllm.svg"
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import tempfile
|
|
4
|
+
import traceback
|
|
5
|
+
|
|
6
|
+
import Orange
|
|
7
|
+
from Orange.data import StringVariable
|
|
8
|
+
from Orange.widgets import widget
|
|
9
|
+
from Orange.widgets.widget import Input, Output
|
|
10
|
+
from AnyQt.QtWidgets import QMessageBox, QApplication
|
|
11
|
+
|
|
12
|
+
from docx import Document
|
|
13
|
+
from docx.shared import Pt as pt_docx
|
|
14
|
+
from pptx import Presentation
|
|
15
|
+
from pptx.util import Inches, Pt
|
|
16
|
+
import pypandoc
|
|
17
|
+
from docx2pdf import convert
|
|
18
|
+
|
|
19
|
+
# Chargement UI
|
|
20
|
+
if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
|
|
21
|
+
from Orange.widgets.orangecontrib.AAIT.utils.import_uic import uic
|
|
22
|
+
else:
|
|
23
|
+
from orangecontrib.AAIT.utils.import_uic import uic
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class OWExportMarkdown(widget.OWWidget):
|
|
27
|
+
name = "OWExportMarkdown"
|
|
28
|
+
description = "Auto-exporte content→(docx,pptx,pdf) au même path (base + extensions)."
|
|
29
|
+
icon = "icons/export_md.png"
|
|
30
|
+
if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
|
|
31
|
+
icon = "icons_dev/export_md.png"
|
|
32
|
+
want_control_area = True
|
|
33
|
+
priority = 9999
|
|
34
|
+
category = "AAIT - Toolbox"
|
|
35
|
+
|
|
36
|
+
class Inputs:
|
|
37
|
+
data = Input("Data", Orange.data.Table)
|
|
38
|
+
|
|
39
|
+
class Outputs:
|
|
40
|
+
data = Output("Data", Orange.data.Table)
|
|
41
|
+
|
|
42
|
+
def __init__(self):
|
|
43
|
+
super().__init__()
|
|
44
|
+
self.data = None
|
|
45
|
+
ui_path = os.path.join(os.path.dirname(__file__), "designer", "owexportmarkdown.ui")
|
|
46
|
+
uic.loadUi(ui_path, baseinstance=self)
|
|
47
|
+
|
|
48
|
+
# -------- helpers headers/footers --------
|
|
49
|
+
def ajouter_en_tete_pied_docx(self, file_path, header_text, footer_text):
|
|
50
|
+
try:
|
|
51
|
+
doc = Document(file_path)
|
|
52
|
+
section = doc.sections[0]
|
|
53
|
+
header = section.header
|
|
54
|
+
p = header.paragraphs[0] if header.paragraphs else header.add_paragraph()
|
|
55
|
+
p.text = header_text
|
|
56
|
+
if p.runs:
|
|
57
|
+
p.runs[0].font.size = pt_docx(10)
|
|
58
|
+
footer = section.footer
|
|
59
|
+
p = footer.paragraphs[0] if footer.paragraphs else footer.add_paragraph()
|
|
60
|
+
p.text = footer_text
|
|
61
|
+
if p.runs:
|
|
62
|
+
p.runs[0].font.size = pt_docx(10)
|
|
63
|
+
doc.save(file_path)
|
|
64
|
+
except Exception:
|
|
65
|
+
# en-tête/pied non bloquants
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
def ajouter_entete_pied_pptx(self, file_path, entete_text, pied_text):
|
|
69
|
+
try:
|
|
70
|
+
prs = Presentation(file_path)
|
|
71
|
+
for slide in prs.slides:
|
|
72
|
+
entete = slide.shapes.add_textbox(Inches(0.3), Inches(0.2), Inches(8), Inches(0.5))
|
|
73
|
+
tf_entete = entete.text_frame
|
|
74
|
+
tf_entete.text = entete_text
|
|
75
|
+
tf_entete.paragraphs[0].font.size = Pt(12)
|
|
76
|
+
tf_entete.paragraphs[0].font.bold = True
|
|
77
|
+
|
|
78
|
+
pied = slide.shapes.add_textbox(Inches(0.3), Inches(6.3), Inches(8), Inches(0.5))
|
|
79
|
+
tf_pied = pied.text_frame
|
|
80
|
+
tf_pied.text = pied_text
|
|
81
|
+
tf_pied.paragraphs[0].font.size = Pt(10)
|
|
82
|
+
prs.save(file_path)
|
|
83
|
+
except Exception:
|
|
84
|
+
pass
|
|
85
|
+
|
|
86
|
+
# -------------- input --------------
|
|
87
|
+
@Inputs.data
|
|
88
|
+
def set_data(self, in_data):
|
|
89
|
+
self.error("")
|
|
90
|
+
if in_data is None:
|
|
91
|
+
self.data = None
|
|
92
|
+
self.Outputs.data.send(None)
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
# On exige au moins 'path'
|
|
96
|
+
if "path" not in in_data.domain:
|
|
97
|
+
self.error("La table d'entrée doit contenir au moins la colonne 'path'.")
|
|
98
|
+
self.Outputs.data.send(None)
|
|
99
|
+
return
|
|
100
|
+
|
|
101
|
+
# Optionnellement 'content'
|
|
102
|
+
self.data = in_data
|
|
103
|
+
try:
|
|
104
|
+
table_out = self.export_all_rows()
|
|
105
|
+
self.Outputs.data.send(table_out)
|
|
106
|
+
except Exception as e:
|
|
107
|
+
tb = traceback.format_exc()
|
|
108
|
+
QMessageBox.critical(self, "Erreur d'export", f"{e}\n\n{tb}")
|
|
109
|
+
self.Outputs.data.send(None)
|
|
110
|
+
|
|
111
|
+
# -------------- core --------------
|
|
112
|
+
def export_all_rows(self):
|
|
113
|
+
base_paths = self.data.get_column("path")
|
|
114
|
+
has_content = "content" in self.data.domain
|
|
115
|
+
file_contents = self.data.get_column("content") if has_content else [None] * len(base_paths)
|
|
116
|
+
|
|
117
|
+
pdf_paths, docx_paths, pptx_paths = [], [], []
|
|
118
|
+
|
|
119
|
+
for i, (md_text, base_path) in enumerate(zip(file_contents, base_paths)):
|
|
120
|
+
base_path = str(base_path or "").strip()
|
|
121
|
+
|
|
122
|
+
# Lecture du contenu si 'content' absent et path en .md
|
|
123
|
+
if not has_content:
|
|
124
|
+
if base_path.lower().endswith(".md"):
|
|
125
|
+
try:
|
|
126
|
+
with open(base_path, "r", encoding="utf-8") as f:
|
|
127
|
+
md_text = f.read()
|
|
128
|
+
# on remplace base_path par le même (on garde la base pour sorties)
|
|
129
|
+
except Exception as e:
|
|
130
|
+
self.error(f"Impossible de lire le fichier : {base_path} ({e})")
|
|
131
|
+
pdf_paths.append("")
|
|
132
|
+
docx_paths.append("")
|
|
133
|
+
pptx_paths.append("")
|
|
134
|
+
continue
|
|
135
|
+
else:
|
|
136
|
+
# pas de content et path non .md -> rien à faire pour cette ligne
|
|
137
|
+
pdf_paths.append("")
|
|
138
|
+
docx_paths.append("")
|
|
139
|
+
pptx_paths.append("")
|
|
140
|
+
continue
|
|
141
|
+
|
|
142
|
+
md_text = (str(md_text or "")).strip()
|
|
143
|
+
|
|
144
|
+
if not md_text or not base_path:
|
|
145
|
+
pdf_paths.append("")
|
|
146
|
+
docx_paths.append("")
|
|
147
|
+
pptx_paths.append("")
|
|
148
|
+
continue
|
|
149
|
+
|
|
150
|
+
# Normaliser la base: enlever extension si présente
|
|
151
|
+
base_no_ext, _ = os.path.splitext(base_path)
|
|
152
|
+
# Créer dossier si nécessaire
|
|
153
|
+
out_dir = os.path.dirname(base_no_ext)
|
|
154
|
+
if out_dir and not os.path.isdir(out_dir):
|
|
155
|
+
os.makedirs(out_dir, exist_ok=True)
|
|
156
|
+
|
|
157
|
+
docx_out = base_no_ext + ".docx"
|
|
158
|
+
pptx_out = base_no_ext + ".pptx"
|
|
159
|
+
pdf_out = base_no_ext + ".pdf"
|
|
160
|
+
|
|
161
|
+
# MD temporaire
|
|
162
|
+
with tempfile.NamedTemporaryFile(mode="w", suffix=".md", delete=False, encoding="utf-8") as tmp:
|
|
163
|
+
tmp.write(md_text)
|
|
164
|
+
tmp_md = tmp.name
|
|
165
|
+
|
|
166
|
+
try:
|
|
167
|
+
# DOCX
|
|
168
|
+
pypandoc.convert_file(tmp_md, to="docx", outputfile=docx_out)
|
|
169
|
+
self.ajouter_en_tete_pied_docx(
|
|
170
|
+
docx_out,
|
|
171
|
+
"Rapport - Orange AI",
|
|
172
|
+
"Page générée automatiquement - Ne pas diffuser"
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# PPTX
|
|
176
|
+
pypandoc.convert_file(tmp_md, to="pptx", outputfile=pptx_out)
|
|
177
|
+
self.ajouter_entete_pied_pptx(
|
|
178
|
+
pptx_out,
|
|
179
|
+
"Orange AI – Présentation",
|
|
180
|
+
"Page générée automatiquement"
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# PDF (docx -> pdf) avec chemin de sortie exact
|
|
184
|
+
try:
|
|
185
|
+
convert(docx_out, pdf_out)
|
|
186
|
+
except Exception:
|
|
187
|
+
# fallback pandoc->pdf (si LaTeX dispo)
|
|
188
|
+
try:
|
|
189
|
+
pypandoc.convert_file(tmp_md, to="pdf", outputfile=pdf_out)
|
|
190
|
+
except Exception:
|
|
191
|
+
self.error(f"Échec conversion PDF pour la ligne {i+1}.")
|
|
192
|
+
pdf_out = ""
|
|
193
|
+
finally:
|
|
194
|
+
try:
|
|
195
|
+
os.remove(tmp_md)
|
|
196
|
+
except Exception:
|
|
197
|
+
pass
|
|
198
|
+
|
|
199
|
+
pdf_paths.append(pdf_out if os.path.isfile(pdf_out) else "")
|
|
200
|
+
docx_paths.append(docx_out if os.path.isfile(docx_out) else "")
|
|
201
|
+
pptx_paths.append(pptx_out if os.path.isfile(pptx_out) else "")
|
|
202
|
+
|
|
203
|
+
# Ajouter colonnes sortie
|
|
204
|
+
table = self.data
|
|
205
|
+
table = table.add_column(StringVariable("output_pdf_path"), pdf_paths)
|
|
206
|
+
table = table.add_column(StringVariable("output_docx_path"), docx_paths)
|
|
207
|
+
table = table.add_column(StringVariable("output_pptx_path"), pptx_paths)
|
|
208
|
+
|
|
209
|
+
return table
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
if __name__ == "__main__":
|
|
213
|
+
app = QApplication(sys.argv)
|
|
214
|
+
w = OWExportMarkdown()
|
|
215
|
+
w.show()
|
|
216
|
+
sys.exit(app.exec() if hasattr(app, "exec") else app.exec_())
|