diff --git a/batch_generate_fiches.py b/IA/00 - fiches_corpus/batch_generate_fiches.py similarity index 100% rename from batch_generate_fiches.py rename to IA/00 - fiches_corpus/batch_generate_fiches.py diff --git a/generate_corpus.py b/IA/00 - fiches_corpus/generate_corpus.py similarity index 100% rename from generate_corpus.py rename to IA/00 - fiches_corpus/generate_corpus.py diff --git a/IA/analyze_graph.py b/IA/01 - corpus_rapport_factuel/analyze_graph.py similarity index 100% rename from IA/analyze_graph.py rename to IA/01 - corpus_rapport_factuel/analyze_graph.py diff --git a/IA/check_paths.py b/IA/01 - corpus_rapport_factuel/check_paths.py similarity index 100% rename from IA/check_paths.py rename to IA/01 - corpus_rapport_factuel/check_paths.py diff --git a/IA/generate_template.py b/IA/01 - corpus_rapport_factuel/generate_template.py similarity index 100% rename from IA/generate_template.py rename to IA/01 - corpus_rapport_factuel/generate_template.py diff --git a/IA/replace_paths.py b/IA/01 - corpus_rapport_factuel/replace_paths.py similarity index 100% rename from IA/replace_paths.py rename to IA/01 - corpus_rapport_factuel/replace_paths.py diff --git a/IA/02 - injection_fiches/README.md b/IA/02 - injection_fiches/README.md new file mode 100644 index 0000000..3779639 --- /dev/null +++ b/IA/02 - injection_fiches/README.md @@ -0,0 +1,90 @@ +# Script d'Injection Automatique pour PrivateGPT + +Ce script permet d'automatiser l'injection de documents dans PrivateGPT à partir d'un répertoire local. Au lieu d'utiliser l'interface utilisateur pour télécharger les fichiers un par un, vous pouvez injecter un dossier entier en une seule commande. + +## Prérequis + +- Python 3.7 ou supérieur +- PrivateGPT installé et fonctionnel sous Docker +- Accès à l'API REST de PrivateGPT (port 8001 par défaut) + +## Installation + +1. Clonez ce dépôt ou téléchargez les fichiers dans un dossier + +2. Installez les dépendances nécessaires : +```bash +pip install requests +``` + +## Utilisation + +Le script s'utilise en ligne de commande avec différentes options : + +```bash +python auto_ingest.py -d REPERTOIRE [-u URL] [-r] [-t THREADS] [--retry RETRY] [--retry-delay RETRY_DELAY] [--timeout TIMEOUT] [--extensions EXT1 EXT2 ...] +``` + +### Options + +- `-d, --directory` : Chemin du répertoire contenant les fichiers à injecter (obligatoire) +- `-u, --url` : URL de l'API PrivateGPT (défaut: http://localhost:8001) +- `-r, --recursive` : Parcourir récursivement les sous-répertoires +- `-t, --threads` : Nombre de threads pour les injections parallèles (défaut: 5) +- `--retry` : Nombre de tentatives en cas d'échec (défaut: 3) +- `--retry-delay` : Délai entre les tentatives en secondes (défaut: 5) +- `--timeout` : Délai d'attente pour chaque requête en secondes (défaut: 300) +- `--extensions` : Liste d'extensions spécifiques à injecter (ex: pdf txt) + +## Exemples d'utilisation + +### Injection simple d'un répertoire + +```bash +python auto_ingest.py -d /chemin/vers/documents +``` + +### Injection récursive avec extensions spécifiques + +```bash +python auto_ingest.py -d /chemin/vers/documents -r --extensions pdf docx txt +``` + +### Injection avec paramètres avancés + +```bash +python auto_ingest.py -d /chemin/vers/documents -r -t 10 --timeout 600 --retry 5 +``` + +## Formats de fichiers supportés + +Par défaut, le script reconnaît et traite les formats suivants : +- PDF (.pdf) +- Documents texte (.txt, .md) +- Documents Microsoft Office (.doc, .docx, .ppt, .pptx, .xls, .xlsx) +- CSV (.csv) +- EPUB (.epub) +- HTML (.html, .htm) + +## Résolution des problèmes + +### Erreur de connexion + +Si vous obtenez des erreurs de connexion, vérifiez que : +1. PrivateGPT est bien en cours d'exécution +2. L'URL est correcte (par défaut: http://localhost:8001) +3. Le port 8001 est accessible et n'est pas bloqué par un pare-feu + +### Erreurs d'injection + +- Si un fichier spécifique ne peut pas être injecté, vérifiez qu'il est d'un format supporté par PrivateGPT +- Pour les fichiers volumineux, vous pouvez augmenter la valeur de `--timeout` +- En cas d'erreurs répétées, augmentez les valeurs de `--retry` et `--retry-delay` + +## Logs + +Le script génère des logs dans : +- La console (stdout) +- Un fichier pgpt_auto_ingest.log dans le répertoire courant + +Ces logs contiennent des informations détaillées sur le processus d'injection. \ No newline at end of file diff --git a/IA/02 - injection_fiches/auto_ingest.py b/IA/02 - injection_fiches/auto_ingest.py new file mode 100755 index 0000000..be0abac --- /dev/null +++ b/IA/02 - injection_fiches/auto_ingest.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Script d'injection automatique de documents pour PrivateGPT + +Ce script parcourt un répertoire spécifié et injecte tous les fichiers +compatibles dans PrivateGPT via son API REST. +""" + +import os +import sys +import time +import argparse +import logging +import requests +from pathlib import Path +from typing import List, Dict, Tuple, Set +from concurrent.futures import ThreadPoolExecutor, as_completed + +# Configuration du logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=[ + logging.StreamHandler(), + logging.FileHandler("pgpt_auto_ingest.log") + ] +) +logger = logging.getLogger(__name__) + +# Extensions de fichiers couramment supportées par PrivateGPT +SUPPORTED_EXTENSIONS = { + '.pdf', '.txt', '.md', '.doc', '.docx', '.ppt', '.pptx', + '.xls', '.xlsx', '.csv', '.epub', '.html', '.htm' +} + +def parse_arguments(): + """Parse les arguments de ligne de commande.""" + parser = argparse.ArgumentParser( + description="Injecte automatiquement tous les fichiers d'un répertoire dans PrivateGPT" + ) + parser.add_argument( + "-d", "--directory", + type=str, + required=True, + help="Chemin du répertoire contenant les fichiers à injecter" + ) + parser.add_argument( + "-u", "--url", + type=str, + default="http://localhost:8001", + help="URL de l'API PrivateGPT (défaut: http://localhost:8001)" + ) + parser.add_argument( + "-r", "--recursive", + action="store_true", + help="Parcourir récursivement les sous-répertoires" + ) + parser.add_argument( + "-t", "--threads", + type=int, + default=5, + help="Nombre de threads pour les injections parallèles (défaut: 5)" + ) + parser.add_argument( + "--retry", + type=int, + default=3, + help="Nombre de tentatives en cas d'échec (défaut: 3)" + ) + parser.add_argument( + "--retry-delay", + type=int, + default=5, + help="Délai entre les tentatives en secondes (défaut: 5)" + ) + parser.add_argument( + "--timeout", + type=int, + default=300, + help="Délai d'attente pour chaque requête en secondes (défaut: 300)" + ) + parser.add_argument( + "--extensions", + nargs="+", + help="Liste d'extensions spécifiques à injecter (ex: .pdf .txt)" + ) + + return parser.parse_args() + +def find_files(directory: str, recursive: bool = False, + extensions: Set[str] = SUPPORTED_EXTENSIONS) -> List[Path]: + """ + Trouve tous les fichiers avec les extensions spécifiées dans le répertoire. + + Args: + directory: Répertoire à scanner + recursive: Si True, parcourt aussi les sous-répertoires + extensions: Ensemble d'extensions de fichier à inclure + + Returns: + Liste des chemins de fichiers trouvés + """ + directory_path = Path(directory) + + if not directory_path.exists() or not directory_path.is_dir(): + logger.error(f"Le répertoire {directory} n'existe pas ou n'est pas un répertoire.") + return [] + + files = [] + + if recursive: + # Parcours récursif + for root, _, filenames in os.walk(directory): + for filename in filenames: + file_path = Path(root) / filename + if file_path.suffix.lower() in extensions: + files.append(file_path) + else: + # Parcours non récursif + for file_path in directory_path.iterdir(): + if file_path.is_file() and file_path.suffix.lower() in extensions: + files.append(file_path) + + return files + +def ingest_file(file_path: Path, pgpt_url: str, timeout: int, + retry_count: int, retry_delay: int) -> Tuple[Path, bool, str]: + """ + Injecte un fichier dans PrivateGPT. + + Args: + file_path: Chemin du fichier à injecter + pgpt_url: URL de base de l'API PrivateGPT + timeout: Délai d'attente pour la requête + retry_count: Nombre de tentatives en cas d'échec + retry_delay: Délai entre les tentatives en secondes + + Returns: + Tuple contenant (chemin_fichier, succès, message) + """ + ingest_url = f"{pgpt_url}/v1/ingest/file" + + for attempt in range(retry_count): + try: + logger.info(f"Injection de {file_path} (tentative {attempt + 1}/{retry_count})") + + with open(file_path, 'rb') as file: + files = {'file': (file_path.name, file, 'application/octet-stream')} + response = requests.post(ingest_url, files=files, timeout=timeout) + + if response.status_code == 200: + result = response.json() + doc_ids = result.get('document_ids', []) + logger.info(f"Succès! {file_path} -> {len(doc_ids)} documents créés") + return file_path, True, f"{len(doc_ids)} documents créés" + else: + error_msg = f"Erreur HTTP {response.status_code}: {response.text}" + logger.warning(error_msg) + if attempt < retry_count - 1: + logger.info(f"Nouvelle tentative dans {retry_delay} secondes...") + time.sleep(retry_delay) + else: + return file_path, False, error_msg + + except Exception as e: + error_msg = f"Exception: {str(e)}" + logger.warning(error_msg) + if attempt < retry_count - 1: + logger.info(f"Nouvelle tentative dans {retry_delay} secondes...") + time.sleep(retry_delay) + else: + return file_path, False, error_msg + + return file_path, False, "Nombre maximum de tentatives atteint" + +def main(): + """Fonction principale.""" + args = parse_arguments() + + # Préparation des extensions si spécifiées + extensions = set(args.extensions) if args.extensions else SUPPORTED_EXTENSIONS + # Assurer que les extensions commencent par un point + extensions = {ext if ext.startswith('.') else f'.{ext}' for ext in extensions} + + logger.info(f"Démarrage de l'injection automatique depuis {args.directory}") + logger.info(f"URL PrivateGPT: {args.url}") + logger.info(f"Mode récursif: {args.recursive}") + logger.info(f"Extensions: {', '.join(extensions)}") + + # Trouver les fichiers + files = find_files(args.directory, args.recursive, extensions) + total_files = len(files) + + if total_files == 0: + logger.warning(f"Aucun fichier trouvé avec les extensions {', '.join(extensions)} dans {args.directory}") + return + + logger.info(f"Trouvé {total_files} fichiers à injecter") + + # Statistiques + successful = 0 + failed = 0 + failed_files = [] + + # Injection des fichiers en parallèle + with ThreadPoolExecutor(max_workers=args.threads) as executor: + futures = { + executor.submit( + ingest_file, + file_path, + args.url, + args.timeout, + args.retry, + args.retry_delay + ): file_path for file_path in files + } + + for future in as_completed(futures): + file_path, success, message = future.result() + if success: + successful += 1 + else: + failed += 1 + failed_files.append((file_path, message)) + + # Afficher la progression + progress = (successful + failed) / total_files * 100 + logger.info(f"Progression: {progress:.1f}% ({successful + failed}/{total_files})") + + # Rapport final + logger.info("="*50) + logger.info("RAPPORT D'INJECTION") + logger.info("="*50) + logger.info(f"Total des fichiers: {total_files}") + logger.info(f"Succès: {successful}") + logger.info(f"Échecs: {failed}") + + if failed > 0: + logger.info("\nDétails des échecs:") + for file_path, message in failed_files: + logger.info(f"- {file_path}: {message}") + + logger.info("="*50) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + logger.info("\nInterruption par l'utilisateur. Arrêt du processus.") + sys.exit(1) + except Exception as e: + logger.error(f"Erreur non gérée: {str(e)}", exc_info=True) + sys.exit(1) diff --git a/IA/02 - injection_fiches/auto_ingest.sh b/IA/02 - injection_fiches/auto_ingest.sh new file mode 100755 index 0000000..8355e1c --- /dev/null +++ b/IA/02 - injection_fiches/auto_ingest.sh @@ -0,0 +1,90 @@ +#!/bin/bash +# Script d'exécution pour auto_ingest.py + +# Vérification des dépendances +check_dependencies() { + # Vérifier Python + if ! command -v python3 &> /dev/null; then + echo "Erreur: Python 3 n'est pas installé ou n'est pas dans le PATH" + exit 1 + fi + + # Vérifier pip et requests + if ! python3 -c "import requests" &> /dev/null; then + echo "Installation de la bibliothèque requests..." + pip3 install requests + if [ $? -ne 0 ]; then + echo "Erreur: Impossible d'installer la bibliothèque requests" + echo "Exécutez manuellement: pip3 install requests" + exit 1 + fi + fi +} + +# Fonction d'aide +show_help() { + echo "Script d'injection automatique pour PrivateGPT" + echo "" + echo "Usage: $0 [options] -d RÉPERTOIRE" + echo "" + echo "Options:" + echo " -d, --directory RÉPERTOIRE Répertoire contenant les fichiers à injecter (obligatoire)" + echo " -u, --url URL URL de l'API PrivateGPT (défaut: http://localhost:8001)" + echo " -r, --recursive Parcourir récursivement les sous-répertoires" + echo " -t, --threads N Nombre de threads pour les injections parallèles (défaut: 5)" + echo " --retry N Nombre de tentatives en cas d'échec (défaut: 3)" + echo " --retry-delay N Délai entre les tentatives en secondes (défaut: 5)" + echo " --timeout N Délai d'attente pour chaque requête en secondes (défaut: 300)" + echo " --extensions EXT1 EXT2 ... Liste d'extensions spécifiques à injecter" + echo " -h, --help Afficher cette aide" + echo "" + echo "Exemple: $0 -d /documents -r --extensions pdf docx" +} + +# Vérifier si aucun argument n'est fourni +if [ $# -eq 0 ]; then + show_help + exit 1 +fi + +# Vérifier l'argument d'aide +for arg in "$@"; do + if [ "$arg" = "-h" ] || [ "$arg" = "--help" ]; then + show_help + exit 0 + fi +done + +# Vérifier la présence de l'argument obligatoire (-d ou --directory) +directory_specified=false +for ((i=1; i<=$#; i++)); do + if [ "${!i}" = "-d" ] || [ "${!i}" = "--directory" ]; then + directory_specified=true + break + fi +done + +if [ "$directory_specified" = false ]; then + echo "Erreur: L'option -d/--directory est obligatoire" + echo "Utilisez -h ou --help pour afficher l'aide" + exit 1 +fi + +# Vérifier les dépendances +check_dependencies + +# Chemin au script Python +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PYTHON_SCRIPT="${SCRIPT_DIR}/auto_ingest.py" + +# Vérifier que le script Python existe +if [ ! -f "$PYTHON_SCRIPT" ]; then + echo "Erreur: Le script auto_ingest.py n'existe pas dans $SCRIPT_DIR" + exit 1 +fi + +# Rendre le script Python exécutable +chmod +x "$PYTHON_SCRIPT" + +# Exécuter le script Python avec tous les arguments +python3 "$PYTHON_SCRIPT" "$@" \ No newline at end of file diff --git a/IA/02 - injection_fiches/docker-compose.yml.example b/IA/02 - injection_fiches/docker-compose.yml.example new file mode 100644 index 0000000..7c570d9 --- /dev/null +++ b/IA/02 - injection_fiches/docker-compose.yml.example @@ -0,0 +1,40 @@ +version: '3.8' + +services: + privategpt: + image: ghcr.io/zylon-ai/private-gpt:latest + container_name: privategpt + ports: + - "8001:8001" + environment: + - PGPT_PROFILES=local + # Décommentez et modifiez ces variables si vous voulez utiliser un modèle différent + # - PGPT_SETTINGS_LLMS_DEFAULT__MODEL=/models/custom-model.gguf + # - PGPT_SETTINGS_EMBEDDING_DEFAULT__MODEL=/models/custom-embedding-model + volumes: + # Volume persistant pour les données + - privategpt-data:/app/local_data + # Montage du répertoire d'auto-injection + - ./documents_to_ingest:/app/documents_to_ingest + # Montage des modèles personnalisés (décommentez si nécessaire) + # - ./custom_models:/app/models + restart: unless-stopped + # Décommentez ces lignes si vous avez un GPU NVIDIA + # deploy: + # resources: + # reservations: + # devices: + # - driver: nvidia + # count: 1 + # capabilities: [gpu] + +volumes: + privategpt-data: + name: privategpt-data + +# Instructions d'utilisation: +# 1. Copiez ce fichier sous le nom "docker-compose.yml" +# 2. Créez un répertoire "documents_to_ingest" à côté du fichier docker-compose.yml +# 3. Placez vos documents à injecter dans ce répertoire +# 4. Lancez avec la commande: docker-compose up -d +# 5. Utilisez le script d'injection: ./auto_ingest.sh -d documents_to_ingest -u http://localhost:8001 \ No newline at end of file diff --git a/IA/02 - injection_fiches/watch_directory.py b/IA/02 - injection_fiches/watch_directory.py new file mode 100755 index 0000000..860139d --- /dev/null +++ b/IA/02 - injection_fiches/watch_directory.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Script de surveillance de répertoire pour l'injection automatique dans PrivateGPT + +Ce script surveille un répertoire et injecte automatiquement les nouveaux fichiers +dans PrivateGPT dès qu'ils sont ajoutés ou modifiés. +""" + +import os +import sys +import time +import logging +import argparse +import subprocess +from pathlib import Path +from typing import Set, Dict, List +from datetime import datetime + +try: + from watchdog.observers import Observer + from watchdog.events import FileSystemEventHandler, FileCreatedEvent, FileModifiedEvent +except ImportError: + print("Bibliothèque 'watchdog' non installée. Installation en cours...") + subprocess.run([sys.executable, "-m", "pip", "install", "watchdog"]) + from watchdog.observers import Observer + from watchdog.events import FileSystemEventHandler, FileCreatedEvent, FileModifiedEvent + +# Configuration du logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=[ + logging.StreamHandler(), + logging.FileHandler("pgpt_watch_directory.log") + ] +) +logger = logging.getLogger(__name__) + +# Extensions de fichiers couramment supportées par PrivateGPT +SUPPORTED_EXTENSIONS = { + '.pdf', '.txt', '.md', '.doc', '.docx', '.ppt', '.pptx', + '.xls', '.xlsx', '.csv', '.epub', '.html', '.htm' +} + +class DocumentHandler(FileSystemEventHandler): + """Gestionnaire d'événements pour les fichiers de documents.""" + + def __init__(self, watch_dir: str, ingest_script: str, pgpt_url: str, + extensions: Set[str], delay: int = 5): + """ + Initialise le gestionnaire d'événements. + + Args: + watch_dir: Répertoire à surveiller + ingest_script: Chemin vers le script d'injection + pgpt_url: URL de l'API PrivateGPT + extensions: Extensions de fichiers à traiter + delay: Délai en secondes à attendre avant le traitement (évite de traiter des fichiers partiellement écrits) + """ + self.watch_dir = os.path.abspath(watch_dir) + self.ingest_script = os.path.abspath(ingest_script) + self.pgpt_url = pgpt_url + self.extensions = extensions + self.delay = delay + + # Queue pour les fichiers en attente de traitement + self.pending_files: Dict[str, float] = {} + + # Vérifier que le script d'injection existe + if not os.path.exists(self.ingest_script): + logger.error(f"Le script d'injection {self.ingest_script} n'existe pas!") + raise FileNotFoundError(f"Script d'injection introuvable: {self.ingest_script}") + + def on_created(self, event): + """Appelé lorsqu'un fichier est créé.""" + if not event.is_directory: + self._handle_file_event(event) + + def on_modified(self, event): + """Appelé lorsqu'un fichier est modifié.""" + if not event.is_directory: + self._handle_file_event(event) + + def _handle_file_event(self, event): + """Traite un événement de fichier (création ou modification).""" + file_path = event.src_path + file_ext = os.path.splitext(file_path)[1].lower() + + # Ignorer les fichiers non supportés + if file_ext not in self.extensions: + return + + # Ignorer les fichiers temporaires et cachés + file_name = os.path.basename(file_path) + if file_name.startswith('.') or file_name.startswith('~') or file_name.endswith('.tmp'): + return + + # Ajouter à la queue avec l'horodatage actuel + self.pending_files[file_path] = time.time() + logger.info(f"Fichier détecté: {file_path} (en attente pendant {self.delay} secondes)") + + def process_pending_files(self): + """Traite les fichiers en attente qui ont dépassé le délai d'attente.""" + current_time = time.time() + files_to_process: List[str] = [] + + # Identifier les fichiers prêts à être traités + for file_path, timestamp in list(self.pending_files.items()): + if current_time - timestamp >= self.delay: + if os.path.exists(file_path): # Vérifier que le fichier existe toujours + files_to_process.append(file_path) + self.pending_files.pop(file_path) + + # Traiter les fichiers par lot + if files_to_process: + self._ingest_files(files_to_process) + + def _ingest_files(self, files: List[str]): + """ + Injecte une liste de fichiers en utilisant le script d'injection. + + Args: + files: Liste des chemins de fichiers à injecter + """ + try: + # Créer un répertoire temporaire pour stocker la liste des fichiers + temp_dir = os.path.join(os.path.dirname(self.ingest_script), "temp") + os.makedirs(temp_dir, exist_ok=True) + + # Créer un fichier de liste + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + list_file = os.path.join(temp_dir, f"files_to_ingest_{timestamp}.txt") + + with open(list_file, "w") as f: + for file_path in files: + f.write(f"{file_path}\n") + + # Construire la commande pour le script d'injection + for file_path in files: + file_dir = os.path.dirname(file_path) + logger.info(f"Injection de {file_path}...") + + cmd = [ + sys.executable, + self.ingest_script, + "-d", file_dir, + "-u", self.pgpt_url, + "--extensions", os.path.splitext(file_path)[1][1:] # Extension sans le point + ] + + # Exécuter la commande + process = subprocess.run( + cmd, + capture_output=True, + text=True + ) + + if process.returncode == 0: + logger.info(f"Injection réussie de {file_path}") + else: + logger.error(f"Échec de l'injection de {file_path}: {process.stderr}") + + except Exception as e: + logger.error(f"Erreur lors de l'injection des fichiers: {str(e)}") + +def parse_arguments(): + """Parse les arguments de ligne de commande.""" + parser = argparse.ArgumentParser( + description="Surveille un répertoire et injecte automatiquement les nouveaux fichiers dans PrivateGPT" + ) + parser.add_argument( + "-d", "--directory", + type=str, + required=True, + help="Chemin du répertoire à surveiller" + ) + parser.add_argument( + "-s", "--script", + type=str, + default=None, + help="Chemin vers le script auto_ingest.py (par défaut: détection automatique)" + ) + parser.add_argument( + "-u", "--url", + type=str, + default="http://localhost:8001", + help="URL de l'API PrivateGPT (défaut: http://localhost:8001)" + ) + parser.add_argument( + "--delay", + type=int, + default=5, + help="Délai en secondes avant de traiter un nouveau fichier (défaut: 5)" + ) + parser.add_argument( + "--extensions", + nargs="+", + help="Liste d'extensions spécifiques à surveiller (ex: pdf txt)" + ) + + return parser.parse_args() + +def main(): + """Fonction principale.""" + args = parse_arguments() + + # Préparation des extensions si spécifiées + extensions = set(args.extensions) if args.extensions else SUPPORTED_EXTENSIONS + # Assurer que les extensions commencent par un point + extensions = {ext if ext.startswith('.') else f'.{ext}' for ext in extensions} + + # Déterminer le chemin du script d'injection + if args.script: + ingest_script = args.script + else: + # Utiliser le script auto_ingest.py dans le même répertoire que ce script + ingest_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "auto_ingest.py") + + # Créer le répertoire de surveillance s'il n'existe pas + watch_dir = os.path.abspath(args.directory) + if not os.path.exists(watch_dir): + logger.info(f"Création du répertoire de surveillance: {watch_dir}") + os.makedirs(watch_dir, exist_ok=True) + + logger.info(f"Démarrage de la surveillance de {watch_dir}") + logger.info(f"URL PrivateGPT: {args.url}") + logger.info(f"Extensions surveillées: {', '.join(extensions)}") + logger.info(f"Délai de traitement: {args.delay} secondes") + + # Initialiser le gestionnaire et l'observateur + event_handler = DocumentHandler( + watch_dir=watch_dir, + ingest_script=ingest_script, + pgpt_url=args.url, + extensions=extensions, + delay=args.delay + ) + + observer = Observer() + observer.schedule(event_handler, path=watch_dir, recursive=True) + observer.start() + + try: + logger.info("Surveillance en cours... (Ctrl+C pour quitter)") + + while True: + # Traiter les fichiers en attente + event_handler.process_pending_files() + time.sleep(1) + + except KeyboardInterrupt: + logger.info("\nInterruption par l'utilisateur. Arrêt de la surveillance.") + observer.stop() + + observer.join() + +if __name__ == "__main__": + try: + main() + except Exception as e: + logger.error(f"Erreur non gérée: {str(e)}", exc_info=True) + sys.exit(1) \ No newline at end of file diff --git a/IA/02 - injection_fiches/watch_directory.sh b/IA/02 - injection_fiches/watch_directory.sh new file mode 100755 index 0000000..15c12d6 --- /dev/null +++ b/IA/02 - injection_fiches/watch_directory.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# Script d'exécution pour watch_directory.py + +# Vérification des dépendances +check_dependencies() { + # Vérifier Python + if ! command -v python3 &> /dev/null; then + echo "Erreur: Python 3 n'est pas installé ou n'est pas dans le PATH" + exit 1 + fi + + # Vérifier les bibliothèques Python requises + python3 -c " +try: + import watchdog +except ImportError: + print('Installation de la bibliothèque watchdog...') + import subprocess, sys + subprocess.run([sys.executable, '-m', 'pip', 'install', 'watchdog']) +" || { + echo "Erreur: Impossible d'installer les dépendances" + exit 1 + } +} + +# Fonction d'aide +show_help() { + echo "Script de surveillance de répertoire pour PrivateGPT" + echo "" + echo "Usage: $0 [options] -d RÉPERTOIRE" + echo "" + echo "Options:" + echo " -d, --directory RÉPERTOIRE Répertoire à surveiller (obligatoire)" + echo " -s, --script CHEMIN Chemin vers le script auto_ingest.py (facultatif)" + echo " -u, --url URL URL de l'API PrivateGPT (défaut: http://localhost:8001)" + echo " --delay N Délai en secondes avant de traiter un nouveau fichier (défaut: 5)" + echo " --extensions EXT1 EXT2 ... Liste d'extensions spécifiques à surveiller" + echo " -h, --help Afficher cette aide" + echo "" + echo "Exemple: $0 -d /documents/à/surveiller --extensions pdf docx" +} + +# Vérifier si aucun argument n'est fourni +if [ $# -eq 0 ]; then + show_help + exit 1 +fi + +# Vérifier l'argument d'aide +for arg in "$@"; do + if [ "$arg" = "-h" ] || [ "$arg" = "--help" ]; then + show_help + exit 0 + fi +done + +# Vérifier la présence de l'argument obligatoire (-d ou --directory) +directory_specified=false +for ((i=1; i<=$#; i++)); do + if [ "${!i}" = "-d" ] || [ "${!i}" = "--directory" ]; then + directory_specified=true + break + fi +done + +if [ "$directory_specified" = false ]; then + echo "Erreur: L'option -d/--directory est obligatoire" + echo "Utilisez -h ou --help pour afficher l'aide" + exit 1 +fi + +# Vérifier les dépendances +check_dependencies + +# Chemin au script Python +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PYTHON_SCRIPT="${SCRIPT_DIR}/watch_directory.py" + +# Vérifier que le script Python existe +if [ ! -f "$PYTHON_SCRIPT" ]; then + echo "Erreur: Le script watch_directory.py n'existe pas dans $SCRIPT_DIR" + exit 1 +fi + +# Rendre le script Python exécutable +chmod +x "$PYTHON_SCRIPT" + +# Message d'information sur l'arrêt +echo "Démarrage de la surveillance..." +echo "Appuyez sur Ctrl+C pour arrêter la surveillance" +echo "" + +# Exécuter le script Python avec tous les arguments +python3 "$PYTHON_SCRIPT" "$@" \ No newline at end of file