vic3610 commited on
Commit
01c4625
·
verified ·
1 Parent(s): 512cdf5

Upload 8 files

Browse files
Files changed (6) hide show
  1. README.md +75 -10
  2. analyze_bob_hf.py +27 -30
  3. bob_gui_hf.py +128 -12
  4. portable_env.py +12 -5
  5. process_bob_hf.py +2 -2
  6. requirements.txt +6 -14
README.md CHANGED
@@ -11,30 +11,95 @@ license: mit
11
  ---
12
 
13
 
14
- # 🎵 BOB Processor
15
 
16
- Application de transcription et d'analyse automatique de fichiers audio.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  ## Fonctionnalités
19
 
20
- - 🎵 Transcription audio avec Whisper
21
- - 🤖 Analyse de contenu avec Hugging Face
22
- - 📋 Classification automatique des formats (P/P+S/QR/MT)
23
- - 📝 Extraction d'informations structurées
 
 
 
 
 
24
 
25
  ## Utilisation
26
 
 
27
  1. Téléchargez un fichier audio (MP3, WAV, etc.)
28
  2. Cliquez sur "Traiter le fichier"
29
  3. Obtenez la transcription et l'analyse automatique
30
 
31
- ## Modèles utilisés
 
 
 
 
 
 
 
 
 
 
32
 
33
- - **Transcription** : Whisper small
34
- - **Analyse** : Modèles Hugging Face (OPT-350M)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
  ## Développement
37
 
38
- Ce projet est conçu pour fonctionner sur Hugging Face Spaces.
 
 
 
 
 
 
 
 
 
39
 
40
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
11
  ---
12
 
13
 
14
+ # 🎵 BOB Processor - Version Hugging Face
15
 
16
+ Application de transcription et d'analyse automatique de fichiers audio utilisant Hugging Face Transformers.
17
+
18
+ ## 🚀 Nouveautés (Mise à jour depuis EXE)
19
+
20
+ ### Améliorations intégrées :
21
+ - ✅ **portable_env.py** : Bootstrap environnement portable avec gestion PyInstaller
22
+ - ✅ **Extraction auteur améliorée** : Support des formats "1 DEMARIA Philippe" → "DEMARIA Philippe"
23
+ - ✅ **Interface GUI avancée** : Suppression automatique des fenêtres console
24
+ - ✅ **Gestion durées audio** : Calcul automatique avec pydub + correction auto P+S/SON
25
+ - ✅ **Variables d'environnement** : Lecture dynamique des modèles depuis l'environnement
26
+ - ✅ **Gestion d'erreurs améliorée** : Encodage UTF-8 robuste
27
+ - ✅ **API factorisée** : Callbacks pour log/progress/cancel dans l'analyse
28
+
29
+ ### Modèles Hugging Face supportés :
30
+ - **Qwen/Qwen2-7B-Instruct** (recommandé) - Excellent pour l'analyse
31
+ - **microsoft/DialoGPT-medium** (plus léger) - Pour PC avec peu de RAM
32
+ - **google/flan-t5-base** (très léger) - Pour tests rapides
33
 
34
  ## Fonctionnalités
35
 
36
+ - 🎵 **Transcription audio** avec Whisper (Small/Medium)
37
+ - 🤖 **Analyse de contenu** avec Hugging Face Transformers
38
+ - 📋 **Classification automatique** des formats :
39
+ - **P** = Papier seul (lecture continue)
40
+ - **P+S** = Papier + Son (avec témoignages/interviews)
41
+ - **QR** = Questions-Réponses (dialogue en direct)
42
+ - **MT** = Micro-Trottoir (opinions publiques)
43
+ - 📝 **Extraction d'informations** : Auteur, Qualification, Titre, Durée
44
+ - 🔍 **Détection automatique** des patterns de contenu
45
 
46
  ## Utilisation
47
 
48
+ ### Interface Gradio (Web)
49
  1. Téléchargez un fichier audio (MP3, WAV, etc.)
50
  2. Cliquez sur "Traiter le fichier"
51
  3. Obtenez la transcription et l'analyse automatique
52
 
53
+ ### Interface GUI (Desktop)
54
+ ```bash
55
+ python bob_gui_hf.py
56
+ ```
57
+
58
+ ### Script en ligne de commande
59
+ ```bash
60
+ python process_bob_hf.py
61
+ ```
62
+
63
+ ## Installation
64
 
65
+ ```bash
66
+ pip install -r requirements.txt
67
+ ```
68
+
69
+ ## Architecture
70
+
71
+ ```
72
+ HUGIN PORTABLE BOB/
73
+ ├── portable_env.py # 🆕 Bootstrap environnement portable
74
+ ├── transcribe_audio.py # Transcription Whisper
75
+ ├── analyze_bob_hf.py # 🆕 Analyse Hugging Face (mis à jour)
76
+ ├── bob_gui_hf.py # 🆕 Interface graphique (améliorée)
77
+ ├── process_bob_hf.py # Orchestrateur principal
78
+ ├── app.py # Interface Gradio pour Hugging Face Spaces
79
+ └── requirements.txt # 🆕 Dépendances nettoyées
80
+ ```
81
+
82
+ ## Configuration
83
+
84
+ Variables d'environnement supportées :
85
+ - `HF_MODEL` : Modèle Hugging Face à utiliser
86
+ - `WHISPER_MODEL` : Modèle Whisper (small/medium/large)
87
+ - `BOB_INPUT_DIR` : Dossier d'entrée des fichiers audio
88
+ - `BOB_TRANSCRIPTIONS_DIR` : Dossier de sortie des transcriptions
89
+ - `BOB_OUTPUT_FILE` : Fichier de résumé final
90
+ - `HF_TOKEN` : Token Hugging Face pour modèles privés
91
 
92
  ## Développement
93
 
94
+ ### Test des améliorations
95
+ ```bash
96
+ python test_ameliorations.py
97
+ ```
98
+
99
+ ### Compatibilité
100
+ - ✅ Hugging Face Spaces
101
+ - ✅ Environnement portable (PyInstaller)
102
+ - ✅ Windows/Linux/macOS
103
+ - ✅ CPU et GPU (détection automatique)
104
 
105
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
analyze_bob_hf.py CHANGED
@@ -11,6 +11,7 @@ from transformers import pipeline, AutoTokenizer, AutoModelForCausalLM
11
  from datetime import datetime
12
  import re
13
  import traceback
 
14
 
15
  # Bootstrap environnement portable
16
  try:
@@ -19,28 +20,39 @@ try:
19
  except Exception:
20
  pass
21
 
 
 
 
 
 
 
22
  # Configuration (via env, avec fallback local)
23
  BASE_DIR = Path(os.environ.get("BOB_BASE_DIR", Path(__file__).parent.parent))
24
  TRANSCRIPTIONS_DIR = Path(os.environ.get("BOB_TRANSCRIPTIONS_DIR", BASE_DIR / "output" / "transcriptions"))
25
  OUTPUT_FILE = Path(os.environ.get("BOB_OUTPUT_FILE", BASE_DIR / "output" / "resume_bob.txt"))
26
  HF_MODEL = os.environ.get("HF_MODEL", "Qwen/Qwen2-7B-Instruct") # Qwen 7B par défaut
27
 
 
 
 
 
28
 
29
  def load_hf_model():
30
  """Charge un modèle Hugging Face"""
31
  try:
32
- print(f"Chargement du modèle Hugging Face: {HF_MODEL}")
 
33
 
34
  # Utiliser pipeline pour plus de simplicité
35
  generator = pipeline(
36
  "text-generation",
37
- model=HF_MODEL,
38
  torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
39
  device_map="auto" if torch.cuda.is_available() else "cpu",
40
  token=os.environ.get("HF_TOKEN") # Pour les modèles privés
41
  )
42
 
43
- print(f"✅ Modèle {HF_MODEL} chargé avec succès")
44
  return generator
45
  except Exception as e:
46
  print(f"❌ Erreur lors du chargement du modèle Hugging Face: {e}")
@@ -351,44 +363,29 @@ def apply_duration_correction(result, duration_seconds, format_indicators=None):
351
  def extract_author_from_filename(filename):
352
  """Extrait le nom du journaliste depuis le nom du fichier"""
353
  try:
 
 
354
  # Nettoyer le nom du fichier
355
  clean_name = filename.replace('_transcription.txt', '').replace('.mp3', '').replace('.MP3', '')
356
 
357
- # Patterns courants pour extraire un nom (prénom + nom)
358
- words = clean_name.split()
359
-
360
- # Chercher une séquence de 2 mots qui commencent par une majuscule
361
- for i in range(len(words) - 1):
362
- word1 = words[i].strip('()[]{}.,;:!?-_')
363
- word2 = words[i + 1].strip('()[]{}.,;:!?-_')
364
-
365
- # Vérifier si les deux mots ressemblent à un prénom + nom
366
- if (len(word1) >= 2 and len(word2) >= 2 and
367
- word1[0].isupper() and word2[0].isupper() and
368
- word1.isalpha() and word2.isalpha()):
369
- return f"{word1} {word2}"
370
 
371
- # Si pas trouvé, chercher le premier mot qui commence par une majuscule
372
- for word in words:
373
- clean_word = word.strip('()[]{}.,;:!?-_')
374
- if len(clean_word) >= 2 and clean_word[0].isupper() and clean_word.isalpha():
375
- # Essayer de trouver le mot suivant
376
- word_index = words.index(word)
377
- if word_index + 1 < len(words):
378
- next_word = words[word_index + 1].strip('()[]{}.,;:!?-_')
379
- if len(next_word) >= 2 and next_word[0].isupper() and next_word.isalpha():
380
- return f"{clean_word} {next_word}"
381
- return clean_word
382
 
383
  return "Inconnu"
384
 
385
  except Exception as e:
386
- print(f"Erreur extraction auteur de {filename}: {e}")
387
  return "Inconnu"
388
 
389
  def get_audio_duration(audio_filename, input_dir):
390
- """Calcule la durée d'un fichier audio en secondes totales"""
391
  try:
 
392
  from pydub import AudioSegment
393
  audio_path = None
394
  audio_extensions = ['.mp3', '.wav', '.m4a', '.flac', '.ogg', '.mp4', '.avi', '.mov']
@@ -415,7 +412,7 @@ def get_audio_duration(audio_filename, input_dir):
415
  return None
416
 
417
  def get_transcription_files(transcriptions_dir):
418
- """Récupère tous les fichiers de transcription"""
419
  if not transcriptions_dir.exists():
420
  print(f"Le dossier {transcriptions_dir} n'existe pas")
421
  return []
 
11
  from datetime import datetime
12
  import re
13
  import traceback
14
+ from dotenv import load_dotenv
15
 
16
  # Bootstrap environnement portable
17
  try:
 
20
  except Exception:
21
  pass
22
 
23
+ # Charger les variables d'environnement
24
+ try:
25
+ load_dotenv(Path(__file__).parent.parent / ".env")
26
+ except Exception:
27
+ pass
28
+
29
  # Configuration (via env, avec fallback local)
30
  BASE_DIR = Path(os.environ.get("BOB_BASE_DIR", Path(__file__).parent.parent))
31
  TRANSCRIPTIONS_DIR = Path(os.environ.get("BOB_TRANSCRIPTIONS_DIR", BASE_DIR / "output" / "transcriptions"))
32
  OUTPUT_FILE = Path(os.environ.get("BOB_OUTPUT_FILE", BASE_DIR / "output" / "resume_bob.txt"))
33
  HF_MODEL = os.environ.get("HF_MODEL", "Qwen/Qwen2-7B-Instruct") # Qwen 7B par défaut
34
 
35
+ def get_hf_model():
36
+ """Récupère le modèle Hugging Face depuis la variable d'environnement"""
37
+ return os.environ.get("HF_MODEL", "Qwen/Qwen2-7B-Instruct")
38
+
39
 
40
  def load_hf_model():
41
  """Charge un modèle Hugging Face"""
42
  try:
43
+ hf_model = get_hf_model() # Lire dynamiquement
44
+ print(f"Chargement du modèle Hugging Face: {hf_model}")
45
 
46
  # Utiliser pipeline pour plus de simplicité
47
  generator = pipeline(
48
  "text-generation",
49
+ model=hf_model,
50
  torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
51
  device_map="auto" if torch.cuda.is_available() else "cpu",
52
  token=os.environ.get("HF_TOKEN") # Pour les modèles privés
53
  )
54
 
55
+ print(f"✅ Modèle {hf_model} chargé avec succès")
56
  return generator
57
  except Exception as e:
58
  print(f"❌ Erreur lors du chargement du modèle Hugging Face: {e}")
 
363
  def extract_author_from_filename(filename):
364
  """Extrait le nom du journaliste depuis le nom du fichier"""
365
  try:
366
+ import re
367
+
368
  # Nettoyer le nom du fichier
369
  clean_name = filename.replace('_transcription.txt', '').replace('.mp3', '').replace('.MP3', '')
370
 
371
+ # Pattern spécifique pour "1 DEMARIA Philippe" -> "DEMARIA Philippe"
372
+ # Supprimer les numéros au début
373
+ clean_name = re.sub(r'^\d+\s+', '', clean_name).strip()
 
 
 
 
 
 
 
 
 
 
374
 
375
+ # Si on a encore quelque chose, c'est probablement un nom
376
+ if clean_name:
377
+ return clean_name
 
 
 
 
 
 
 
 
378
 
379
  return "Inconnu"
380
 
381
  except Exception as e:
382
+ print(f"Erreur extraction auteur: {e}")
383
  return "Inconnu"
384
 
385
  def get_audio_duration(audio_filename, input_dir):
386
+ """Calcule la durée d'un fichier audio en secondes totales (version unique)"""
387
  try:
388
+ # portable_env a déjà injecté ffmpeg dans le PATH si nécessaire
389
  from pydub import AudioSegment
390
  audio_path = None
391
  audio_extensions = ['.mp3', '.wav', '.m4a', '.flac', '.ogg', '.mp4', '.avi', '.mov']
 
412
  return None
413
 
414
  def get_transcription_files(transcriptions_dir):
415
+ """Récupère tous les fichiers de transcription (unique)"""
416
  if not transcriptions_dir.exists():
417
  print(f"Le dossier {transcriptions_dir} n'existe pas")
418
  return []
bob_gui_hf.py CHANGED
@@ -28,17 +28,80 @@ except Exception as _e:
28
  from transcribe_audio import transcribe_file, load_whisper_model, get_audio_files
29
  from analyze_bob_hf import analyze_files_hf # Version Hugging Face
30
 
31
- # Masquer la console Windows si présente
32
  def _hide_windows_console():
33
  if os.name == 'nt':
34
  try:
35
  import ctypes
36
  hwnd = ctypes.windll.kernel32.GetConsoleWindow()
37
  if hwnd:
 
38
  ctypes.windll.user32.ShowWindow(hwnd, 0)
39
  except Exception:
40
  pass
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  class WorkerThread(QThread):
43
  """Thread pour le traitement en arrière-plan"""
44
  progress = pyqtSignal(int)
@@ -236,18 +299,62 @@ class BOBProcessorGUI(QMainWindow):
236
  config_layout.addWidget(self.output_btn, 1, 2)
237
 
238
  # Options
239
- model_label = QLabel("🧠 Modèle Whisper:")
240
  model_label.setFont(QFont("Arial", 11, QFont.Bold))
241
  config_layout.addWidget(model_label, 2, 0)
242
  self.model_combo = QComboBox()
243
  self.model_combo.setFont(QFont("Arial", 11))
244
  self.model_combo.addItems([
245
- "medium (recommandé)",
246
- "small (plus rapide mais moins précis)",
247
- "large (plus précis mais plus lent)",
248
  ])
249
- self.model_combo.setCurrentText("medium (recommandé)")
250
  self.model_combo.setStyleSheet("font-size: 11pt; padding: 5px;")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  config_layout.addWidget(self.model_combo, 2, 1)
252
 
253
  # Sélecteur de modèle HF pour l'analyse
@@ -353,18 +460,26 @@ class BOBProcessorGUI(QMainWindow):
353
 
354
  # Configuration du thread de traitement
355
  model_text = self.model_combo.currentText()
356
- whisper_model = model_text.split()[0] # Prendre le premier mot (small/medium/large)
 
 
 
 
 
357
 
358
  # HF selection -> nom de modèle Hugging Face
359
  hf_choice = self.hf_combo.currentText()
360
- if "Llama-3.2-1B" in hf_choice:
361
- hf_model_name = "meta-llama/Llama-3.2-1B-Instruct"
 
 
 
362
  fast_mode = True
363
- elif "Phi-3" in hf_choice:
364
- hf_model_name = "microsoft/Phi-3-mini-4k-instruct"
365
  fast_mode = True
366
  else:
367
- hf_model_name = "mistralai/Mistral-7B-Instruct-v0.3"
368
  fast_mode = False
369
 
370
  # Configuration des variables d'environnement
@@ -438,6 +553,7 @@ class BOBProcessorGUI(QMainWindow):
438
 
439
  def main():
440
  _hide_windows_console()
 
441
  app = QApplication(sys.argv)
442
  app.setStyle('Fusion')
443
 
 
28
  from transcribe_audio import transcribe_file, load_whisper_model, get_audio_files
29
  from analyze_bob_hf import analyze_files_hf # Version Hugging Face
30
 
31
+ # Masquer la console Windows si présente (exe console) pour n'afficher que le GUI
32
  def _hide_windows_console():
33
  if os.name == 'nt':
34
  try:
35
  import ctypes
36
  hwnd = ctypes.windll.kernel32.GetConsoleWindow()
37
  if hwnd:
38
+ # 0 = SW_HIDE
39
  ctypes.windll.user32.ShowWindow(hwnd, 0)
40
  except Exception:
41
  pass
42
 
43
+ def _suppress_console_windows():
44
+ """Supprime toutes les fenêtres console qui pourraient s'ouvrir pendant l'exécution"""
45
+ if os.name == 'nt':
46
+ try:
47
+ import subprocess
48
+ import ctypes
49
+ from ctypes import wintypes
50
+
51
+ # Forcer tous les subprocess à ne pas créer de fenêtre
52
+ original_popen_init = subprocess.Popen.__init__
53
+ def _hidden_popen_init(self, *args, **kwargs):
54
+ # Forcer la suppression de toutes les fenêtres
55
+ if 'startupinfo' not in kwargs:
56
+ kwargs['startupinfo'] = subprocess.STARTUPINFO()
57
+ kwargs['startupinfo'].dwFlags |= subprocess.STARTF_USESHOWWINDOW
58
+ kwargs['startupinfo'].wShowWindow = subprocess.SW_HIDE
59
+ if 'creationflags' not in kwargs:
60
+ kwargs['creationflags'] = 0
61
+ kwargs['creationflags'] |= subprocess.CREATE_NO_WINDOW | 0x08000000 # CREATE_NO_WINDOW + DETACHED_PROCESS
62
+ return original_popen_init(self, *args, **kwargs)
63
+ subprocess.Popen.__init__ = _hidden_popen_init
64
+
65
+ # Aussi pour os.system et os.popen
66
+ original_system = os.system
67
+ def hidden_system(cmd):
68
+ return subprocess.call(cmd, shell=True, creationflags=subprocess.CREATE_NO_WINDOW)
69
+ os.system = hidden_system
70
+
71
+ # Patch global pour tous les appels système
72
+ import atexit
73
+ def hide_all_console_windows():
74
+ try:
75
+ # Enum toutes les fenêtres et cache celles qui sont des consoles
76
+ def enum_windows_proc(hwnd, lParam):
77
+ try:
78
+ class_name = ctypes.create_unicode_buffer(256)
79
+ ctypes.windll.user32.GetClassNameW(hwnd, class_name, 256)
80
+ if class_name.value == "ConsoleWindowClass":
81
+ ctypes.windll.user32.ShowWindow(hwnd, 0) # SW_HIDE
82
+ except:
83
+ pass
84
+ return True
85
+
86
+ EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, wintypes.HWND, wintypes.LPARAM)
87
+ enum_proc = EnumWindowsProc(enum_windows_proc)
88
+ ctypes.windll.user32.EnumWindows(enum_proc, 0)
89
+ except:
90
+ pass
91
+
92
+ # Démarrer un timer pour cacher les fenêtres en continu
93
+ import threading
94
+ def console_hider():
95
+ while True:
96
+ hide_all_console_windows()
97
+ time.sleep(0.1) # Vérifier toutes les 100ms
98
+
99
+ timer_thread = threading.Thread(target=console_hider, daemon=True)
100
+ timer_thread.start()
101
+
102
+ except Exception:
103
+ pass
104
+
105
  class WorkerThread(QThread):
106
  """Thread pour le traitement en arrière-plan"""
107
  progress = pyqtSignal(int)
 
299
  config_layout.addWidget(self.output_btn, 1, 2)
300
 
301
  # Options
302
+ model_label = QLabel(" Modèle de transcription:")
303
  model_label.setFont(QFont("Arial", 11, QFont.Bold))
304
  config_layout.addWidget(model_label, 2, 0)
305
  self.model_combo = QComboBox()
306
  self.model_combo.setFont(QFont("Arial", 11))
307
  self.model_combo.addItems([
308
+ "Whisper Small : 2x plus rapide (recommandé)",
309
+ "Whisper Medium : utile si qualité audio faible",
 
310
  ])
311
+ self.model_combo.setCurrentText("Whisper Small : 2x plus rapide (recommandé)")
312
  self.model_combo.setStyleSheet("font-size: 11pt; padding: 5px;")
313
+ # Tooltip explicative pour le choix du modèle Whisper
314
+ self.model_combo.setToolTip(
315
+ "🎙️ Choix du modèle de transcription audio :\n\n"
316
+ "• Small : Recommandé dans la plupart des cas\n"
317
+ " - 2x plus rapide que Medium\n"
318
+ " - Bonne précision pour un audio de qualité correcte\n"
319
+ " - Utilise moins de ressources\n\n"
320
+ "• Medium : Pour audio de mauvaise qualité\n"
321
+ " - Plus précis mais 2x plus lent\n"
322
+ " - Utilisez si Small donne de mauvais résultats\n"
323
+ " - Recommandé pour enregistrements bruyants"
324
+ )
325
+ config_layout.addWidget(self.model_combo, 2, 1)
326
+
327
+ # Sélecteur de modèle HF pour l'analyse
328
+ hf_label = QLabel("🧠 Modèle HF (analyse textuelle):")
329
+ hf_label.setFont(QFont("Arial", 11, QFont.Bold))
330
+ config_layout.addWidget(hf_label, 3, 0)
331
+ self.hf_combo = QComboBox()
332
+ self.hf_combo.setFont(QFont("Arial", 11))
333
+ self.hf_combo.addItems([
334
+ "Qwen/Qwen2-7B-Instruct (recommandé)",
335
+ "microsoft/DialoGPT-medium (plus léger)",
336
+ "google/flan-t5-base (très léger)",
337
+ ])
338
+ self.hf_combo.setCurrentText("Qwen/Qwen2-7B-Instruct (recommandé)")
339
+ self.hf_combo.setStyleSheet("font-size: 11pt; padding: 5px;")
340
+ # Tooltip explicative pour le choix du modèle
341
+ self.hf_combo.setToolTip(
342
+ "💡 Choix du modèle d'analyse Hugging Face :\n\n"
343
+ "• Qwen2-7B : Recommandé, excellent pour l'analyse\n"
344
+ " Bonne précision, nécessite plus de ressources\n\n"
345
+ "• DialoGPT-medium : Modèle plus léger\n"
346
+ " Utilisez si vous avez peu de RAM\n\n"
347
+ "• FLAN-T5-base : Très léger\n"
348
+ " Pour PC peu puissants ou tests rapides"
349
+ )
350
+ config_layout.addWidget(self.hf_combo, 3, 1)
351
+
352
+ # Aide: format des noms de fichiers MP3
353
+ hint = QLabel("ℹ️ Les fichiers MP3 doivent contenir le nom du journaliste pour extraire l'auteur (ex: 'Marie Dupont.mp3').")
354
+ hint.setWordWrap(True)
355
+ hint.setFont(QFont("Arial", 9))
356
+ hint.setStyleSheet("color: #8c0000; padding-top: 6px;")
357
+ config_layout.addWidget(hint, 4, 0, 1, 3)
358
  config_layout.addWidget(self.model_combo, 2, 1)
359
 
360
  # Sélecteur de modèle HF pour l'analyse
 
460
 
461
  # Configuration du thread de traitement
462
  model_text = self.model_combo.currentText()
463
+ if "Small" in model_text:
464
+ whisper_model = "small"
465
+ elif "Medium" in model_text:
466
+ whisper_model = "medium"
467
+ else:
468
+ whisper_model = "small" # défaut
469
 
470
  # HF selection -> nom de modèle Hugging Face
471
  hf_choice = self.hf_combo.currentText()
472
+ if "Qwen2-7B" in hf_choice:
473
+ hf_model_name = "Qwen/Qwen2-7B-Instruct"
474
+ fast_mode = False
475
+ elif "DialoGPT" in hf_choice:
476
+ hf_model_name = "microsoft/DialoGPT-medium"
477
  fast_mode = True
478
+ elif "flan-t5" in hf_choice:
479
+ hf_model_name = "google/flan-t5-base"
480
  fast_mode = True
481
  else:
482
+ hf_model_name = "Qwen/Qwen2-7B-Instruct"
483
  fast_mode = False
484
 
485
  # Configuration des variables d'environnement
 
553
 
554
  def main():
555
  _hide_windows_console()
556
+ _suppress_console_windows() # Suppression avancée des consoles
557
  app = QApplication(sys.argv)
558
  app.setStyle('Fusion')
559
 
portable_env.py CHANGED
@@ -8,6 +8,7 @@ offre un point unique pour configurer les variables d'environnement.
8
  from __future__ import annotations
9
 
10
  import os
 
11
  from pathlib import Path
12
 
13
 
@@ -30,9 +31,15 @@ def setup_portable_env(base_dir: Path | None = None, force_ollama_portable: bool
30
  Retourne base_dir normalisé.
31
  """
32
  if base_dir is None:
33
- # base_dir = racine du projet (.. depuis EXE)
34
- here = Path(__file__).resolve().parent
35
- base_dir = (here.parent).resolve()
 
 
 
 
 
 
36
 
37
  # Expo pour d'autres modules
38
  os.environ.setdefault("BOB_BASE_DIR", str(base_dir))
@@ -77,8 +84,8 @@ def setup_portable_env(base_dir: Path | None = None, force_ollama_portable: bool
77
 
78
  if force_ollama_portable:
79
  os.environ["BOB_FORCE_PORTABLE_OLLAMA"] = "1"
80
- # Permettre override externe, sinon 11435
81
- portable_host = os.environ.get("PORTABLE_OLLAMA_HOST", "http://localhost:11435")
82
  os.environ["OLLAMA_HOST"] = portable_host
83
 
84
  return base_dir
 
8
  from __future__ import annotations
9
 
10
  import os
11
+ import sys
12
  from pathlib import Path
13
 
14
 
 
31
  Retourne base_dir normalisé.
32
  """
33
  if base_dir is None:
34
+ # Détection robuste du répertoire de base (compatible PyInstaller)
35
+ if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
36
+ # Application packagée avec PyInstaller
37
+ # sys.executable pointe vers BOB.exe dans le bon dossier
38
+ base_dir = Path(sys.executable).parent.resolve()
39
+ else:
40
+ # Développement normal
41
+ here = Path(__file__).resolve().parent
42
+ base_dir = (here.parent).resolve()
43
 
44
  # Expo pour d'autres modules
45
  os.environ.setdefault("BOB_BASE_DIR", str(base_dir))
 
84
 
85
  if force_ollama_portable:
86
  os.environ["BOB_FORCE_PORTABLE_OLLAMA"] = "1"
87
+ # Permettre override externe, sinon 11434 (port standard Ollama)
88
+ portable_host = os.environ.get("PORTABLE_OLLAMA_HOST", "http://localhost:11434")
89
  os.environ["OLLAMA_HOST"] = portable_host
90
 
91
  return base_dir
process_bob_hf.py CHANGED
@@ -87,7 +87,7 @@ def run_script(script_path, step_name, python_executable=None):
87
  capture_output=True,
88
  text=True,
89
  encoding='utf-8',
90
- errors='replace'
91
  )
92
 
93
  end_time = time.time()
@@ -187,7 +187,7 @@ def main():
187
 
188
  print()
189
 
190
- # Déterminer l'exécutable Python
191
  python_exe = sys.executable
192
  print(f"🐍 Utilisation de Python: {python_exe}")
193
  print()
 
87
  capture_output=True,
88
  text=True,
89
  encoding='utf-8',
90
+ errors='replace' # Gérer les erreurs d'encodage
91
  )
92
 
93
  end_time = time.time()
 
187
 
188
  print()
189
 
190
+ # Déterminer l'exécutable Python (le même que celui utilisé actuellement)
191
  python_exe = sys.executable
192
  print(f"🐍 Utilisation de Python: {python_exe}")
193
  print()
requirements.txt CHANGED
@@ -6,24 +6,16 @@ bitsandbytes>=0.41.0 # Pour quantization 4-bit
6
  sentencepiece>=0.1.99
7
  protobuf<=3.20.3 # Pour compatibilité avec certains modèles
8
 
9
- # Dépendances existantes
10
  openai-whisper>=20231117
11
  pydub>=0.25.1
12
- PyQt5>=5.15.0
13
- python-dotenv>=1.0.0
14
-
15
- # Pour l'environnement portable
16
- numpy>=1.21.0
17
- scipy>=1.7.0
18
 
 
 
19
  gradio>=4.0.0
20
- openai-whisper>=20231117
21
- torch>=2.0.0
22
- transformers>=4.35.0
23
- accelerate>=0.20.0
24
- pydub>=0.25.1
25
  numpy>=1.21.0
26
  scipy>=1.7.0
27
- python-dotenv>=1.0.0
28
- sentencepiece>=0.1.99
29
 
 
6
  sentencepiece>=0.1.99
7
  protobuf<=3.20.3 # Pour compatibilité avec certains modèles
8
 
9
+ # Dépendances audio et transcription
10
  openai-whisper>=20231117
11
  pydub>=0.25.1
 
 
 
 
 
 
12
 
13
+ # Interface utilisateur
14
+ PyQt5>=5.15.0
15
  gradio>=4.0.0
16
+
17
+ # Utilitaires
18
+ python-dotenv>=1.0.0
 
 
19
  numpy>=1.21.0
20
  scipy>=1.7.0
 
 
21