<br />
<b>Warning</b>:  Undefined variable $auth in <b>/home/pevo0181/public_html/pia-soft.com/cleania/routes/index.php</b> on line <b>542</b><br />
<br />
<b>Warning</b>:  Trying to access array offset on value of type null in <b>/home/pevo0181/public_html/pia-soft.com/cleania/routes/index.php</b> on line <b>542</b><br />
import os
import pypdf  # Utiliser directement pypdf
from gtts import gTTS
from django.conf import settings
from django.utils import timezone
import uuid
from .models import Documents, Audios
from PIL import Image
import docx
import os
import tempfile
import io
import unicodedata
import re
from pprint import pprint
import sys

def extract_text_from_pdf(pdf_file):
    """Extraire le texte d'un fichier PDF"""
    try:
        pdf_reader = pypdf.PdfReader(pdf_file)
        text = ""
        
        for page_num in range(len(pdf_reader.pages)):
            page = pdf_reader.pages[page_num]
            page_text = page.extract_text()
            if page_text:
                text += page_text + "\n"
        
        return text.strip() if text.strip() else "Aucun texte extrait du PDF"
    except Exception as e:
        raise Exception(f"Erreur lors de l'extraction du texte: {str(e)}")

def text_to_speech(text, voice_type='female_fr', filename=None):
    """Convertir le texte en audio avec gTTS"""
    try:
        # Vérifier que le texte n'est pas vide
        if not text or len(text.strip()) == 0 or text == "Aucun texte extrait du PDF":
            # Créer un message d'erreur audio
            text = "Désolé, aucun texte n'a pu être extrait de ce document PDF."
        
        # Déterminer la langue
        lang = 'fr'
        
        # Créer l'objet gTTS
        tts = gTTS(text=text, lang=lang, slow=False)
        
        # Générer un nom de fichier unique
        if not filename:
            filename = f"audio_{uuid.uuid4().hex[:10]}.mp3"
        
        audio_path = os.path.join(settings.MEDIA_ROOT, 'audios', filename)
        
        # Créer le dossier audios s'il n'existe pas
        os.makedirs(os.path.dirname(audio_path), exist_ok=True)
        
        # Sauvegarder le fichier audio
        tts.save(audio_path)
        
        # Calculer la durée approximative
        duration = max(10, int(len(text) * 0.06))
        
        return f"audios/{filename}", duration
        
    except Exception as e:
        raise Exception(f"Erreur lors de la synthèse vocale: {str(e)}")

def convert_document_to_audio(document_id, voice_type='female_fr'):
    """Fonction principale de conversion text audio -> audio"""
    try:
        # Récupérer le document
        document = Documents.objects.get(id=document_id)
                
        text_content = document.text_content
        
        # Convertir le texte en audio
        audio_filename = f"doc_{document_id}_{uuid.uuid4().hex[:8]}.mp3"
        audio_file_path, duration = text_to_speech(text_content, voice_type, audio_filename)
        
        # Créer l'enregistrement audio
        audio = Audios(
            document=document,
            file_path=audio_file_path,
            duration=duration,
            voice_type=voice_type,
            created_at=timezone.now(),
            updated_at=timezone.now()
        )
        audio.save()
        
        # Marquer le document comme traité
        document.status = 'processed'
        document.save()
        
        return audio
        
    except Exception as e:
        # Marquer le document en erreur
        document = Documents.objects.get(id=document_id)
        document.status = 'pending'
        document.save()
        raise e
    
def text_to_speech_stream(text, lang='fr'):
    """
    Convertir le texte en flux audio temporaire avec gTTS (sans sauvegarde)
    """
    try:
        # Limiter la longueur du texte pour gTTS (environ 5000 caractères max)
        if len(text) > 4000:
            text = text[:4000] + "... [texte tronqué]"
        
        # Utiliser gTTS pour la conversion
        tts = gTTS(text=text, lang=lang, slow=False)
        
        # Sauvegarder dans un fichier temporaire
        with tempfile.NamedTemporaryFile(delete=False, suffix='.mp3') as temp_audio:
            temp_path = temp_audio.name
        
        tts.save(temp_path)
        
        # Lire le fichier temporaire
        with open(temp_path, 'rb') as f:
            audio_data = f.read()
        
        # Nettoyer le fichier temporaire
        os.unlink(temp_path)
        
        return audio_data
        
    except Exception as e:
        raise Exception(f"Erreur lors de la conversion audio: {str(e)}")

def text_to_speech(text, filename=None, lang='fr'):
    """
    Convertir le texte en fichier audio (pour sauvegarde)
    """
    try:
        # Limiter la longueur du texte
        if len(text) > 4000:
            text = text[:4000] + "... [texte tronqué]"
        
        tts = gTTS(text=text, lang=lang, slow=False)
        
        # Générer le chemin du fichier
        if not filename:
            filename = f"audio_{uuid.uuid4().hex[:100]}.mp3"  # uuid est maintenant importé
        
        file_path = os.path.join('audios', filename)
        full_path = os.path.join(settings.MEDIA_ROOT, file_path)
        
        # Créer le dossier si nécessaire
        os.makedirs(os.path.dirname(full_path), exist_ok=True)
        
        # Sauvegarder le fichier
        tts.save(full_path)
        
        # Calculer la durée (approximative - 10 caractères par seconde)
        duration = max(1, len(text) // 10)
        
        return file_path, duration
        
    except Exception as e:
        raise Exception(f"Erreur lors de la sauvegarde audio: {str(e)}")
    




# ============================================
# OPTION 2: EasyOCR (Pure Python - Recommandé)
# ============================================
def extract_with_easyocr(image):
    """
    OCR avec EasyOCR - Pure Python, fonctionne partout
    Installation: pip install easyocr
    """
    import easyocr
    import numpy as np
    
    # Créer le lecteur (cache automatique)
    reader = easyocr.Reader(['fr', 'en'], gpu=False)
    
    # Convertir PIL Image en numpy array
    img_array = np.array(image)
    
    # Extraire le texte
    results = reader.readtext(img_array)
    text = "\n".join([result[1] for result in results])
    
    return text


# ============================================
# OPTION 3: Google Cloud Vision API
# ============================================
def extract_with_google_vision(image_path):
    """
    OCR avec Google Cloud Vision API
    Installation: pip install google-cloud-vision
    """
    from google.cloud import vision
    
    client = vision.ImageAnnotatorClient()
    
    with open(image_path, 'rb') as image_file:
        content = image_file.read()
    
    image = vision.Image(content=content)
    response = client.text_detection(image=image)
    texts = response.text_annotations
    
    if texts:
        return texts[0].description
    return ""


# ============================================
# OPTION 4: OCR.space API (Gratuit)
# ============================================
def extract_with_ocrspace(image_path):
    """
    OCR avec OCR.space API (gratuit jusqu'à 25000 requêtes/mois)
    Inscription: https://ocr.space/ocrapi
    """
    import requests
    
    api_key = getattr(settings, 'OCRSPACE_API_KEY', 'K87899142388957')  # Clé de test
    
    with open(image_path, 'rb') as f:
        response = requests.post(
            'https://api.ocr.space/parse/image',
            files={'file': f},
            data={
                'apikey': api_key,
                'language': 'fre',  # Français
                'isOverlayRequired': False,
            }
        )
    
    result = response.json()
    if result.get('ParsedResults'):
        return result['ParsedResults'][0]['ParsedText']
    return ""


# ============================================
# SÉLECTEUR AUTOMATIQUE D'OCR
# ============================================
def get_ocr_engine():
    """
    Choisit automatiquement le meilleur moteur OCR disponible
    Ordre de préférence: EasyOCR > Tesseract > OCR.space API
    """
    ocr_engine = getattr(settings, 'OCR_ENGINE', 'auto')
    
    if ocr_engine == 'auto':
        # Essayer EasyOCR d'abord
        try:
            import easyocr
            return 'easyocr'
        except ImportError:
            pass
        
        # Puis Tesseract
        try:
            import pytesseract
            pytesseract.get_tesseract_version()
            return 'tesseract'
        except:
            pass
        
        # Sinon API externe
        return 'ocrspace'
    
    return ocr_engine


def extract_text_from_image(image_path):
    """Extraire le texte d'une image avec le meilleur OCR disponible"""
    try:
        engine = get_ocr_engine()
        print(f"🔍 Utilisation du moteur OCR: {engine}")
        
        img = None
        if engine == 'easyocr':
            img = Image.open(image_path)
            result = extract_with_easyocr(img)
            if img:
                img.close()
            return result
        
        elif engine == 'tesseract':
            img = Image.open(image_path)
            result = extract_with_tesseract(img)
            if img:
                img.close()
            return result
        
        elif engine == 'ocrspace':
            return extract_with_ocrspace(image_path)
        
        elif engine == 'google':
            return extract_with_google_vision(image_path)
        
        else:
            raise Exception(f"Moteur OCR inconnu: {engine}")
    
    except Exception as e:
        raise Exception(f"Erreur OCR: {str(e)}")


def extract_text_from_docx(docx_file):
    """Extraire le texte d'un fichier Word"""
    try:
        doc = docx.Document(docx_file)
        text = []
        for paragraph in doc.paragraphs:
            if paragraph.text.strip():
                text.append(paragraph.text)
        return "\n".join(text) if text else "Aucun texte trouvé dans le document Word"
    except Exception as e:
        raise Exception(f"Erreur lecture Word: {str(e)}")


def extract_text_from_pdf(pdf_file):
    """
    Extraire le texte d'un fichier PDF
    Gère les PDFs normaux ET les PDFs scannés (avec OCR)
    Utilise PyMuPDF (fitz) au lieu de pdf2image pour éviter poppler
    """
    try:
        # ÉTAPE 1: Essayer l'extraction normale avec pypdf
        pdf_reader = pypdf.PdfReader(pdf_file)
        text = ""
        
        for page_num in range(len(pdf_reader.pages)):
            page = pdf_reader.pages[page_num]
            page_text = page.extract_text()
            if page_text:
                text += page_text + "\n"
        
        # ÉTAPE 2: Si pas de texte, utiliser OCR avec PyMuPDF
        if not text.strip():
            print("📄 PDF scanné détecté, utilisation de l'OCR avec PyMuPDF...")
            
            # Essayer d'importer PyMuPDF
            try:
                import fitz  # PyMuPDF
            except ImportError:
                raise Exception(
                    "PyMuPDF n'est pas installé. Installez-le avec: pip install PyMuPDF"
                )
            
            # Sauvegarder temporairement le PDF
            with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp_file:
                pdf_file.seek(0)
                tmp_file.write(pdf_file.read())
                tmp_path = tmp_file.name
            
            doc = None
            try:
                # Ouvrir le PDF avec PyMuPDF
                doc = fitz.open(tmp_path)
                
                # Extraire chaque page comme image et appliquer l'OCR
                for page_num in range(len(doc)):
                    print(f"🔍 OCR sur page {page_num + 1}/{len(doc)}...")
                    
                    # Obtenir la page
                    page = doc[page_num]
                    
                    # Convertir en image (pixmap)
                    pix = page.get_pixmap(matrix=fitz.Matrix(2, 2))  # 2x zoom pour meilleure qualité
                    
                    # Convertir pixmap en PIL Image
                    img_data = pix.tobytes("png")
                    img = Image.open(io.BytesIO(img_data))
                    
                    # Sauvegarder temporairement l'image
                    img_temp_path = None
                    try:
                        with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as img_file:
                            img_temp_path = img_file.name
                            img.save(img_temp_path, 'PNG')
                        
                        # OCR sur l'image
                        page_text = extract_text_from_image(img_temp_path)
                        text += page_text + "\n"
                    finally:
                        # Nettoyer l'image temporaire
                        if img_temp_path and os.path.exists(img_temp_path):
                            try:
                                os.remove(img_temp_path)
                            except:
                                pass
                
            finally:
                # IMPORTANT: Fermer le document avant de supprimer le fichier
                if doc:
                    doc.close()
                
                # Attendre un peu pour Windows
                import time
                time.sleep(0.1)
                
                # Nettoyer le PDF temporaire
                if os.path.exists(tmp_path):
                    try:
                        os.remove(tmp_path)
                    except Exception as e:
                        print(f"⚠️ Impossible de supprimer {tmp_path}: {e}")
        
        return text.strip() if text.strip() else "Aucun texte extrait du PDF"
    
    except Exception as e:
        raise Exception(f"Erreur lors de l'extraction du texte: {str(e)}")


def extract_text_from_file(file_object, filename):
    """
    Fonction universelle pour extraire le texte de n'importe quel fichier
    Supporte: PDF, Images (JPG, PNG, etc.), DOCX
    """
    try:
        file_ext = filename.lower().split('.')[-1]
        
        # PDFs (normaux ou scannés)
        if file_ext == 'pdf':
            return extract_text_from_pdf(file_object)
        
        # Documents Word
        elif file_ext in ['docx', 'doc']:
            return extract_text_from_docx(file_object)
        
        # Images (OCR)
        elif file_ext in ['jpg', 'jpeg', 'png', 'bmp', 'tiff', 'tif']:
            # Sauvegarder temporairement l'image
            tmp_path = None
            try:
                with tempfile.NamedTemporaryFile(delete=False, suffix=f'.{file_ext}') as tmp_file:
                    tmp_path = tmp_file.name
                    file_object.seek(0)
                    tmp_file.write(file_object.read())
                
                text = extract_text_from_image(tmp_path)
                return text
            finally:
                # Nettoyer le fichier temporaire
                if tmp_path and os.path.exists(tmp_path):
                    try:
                        os.remove(tmp_path)
                    except Exception as e:
                        print(f"⚠️ Impossible de supprimer {tmp_path}: {e}")
        
        else:
            return f"Format de fichier non supporté: {file_ext}"
    
    except Exception as e:
        raise Exception(f"Erreur extraction: {str(e)}")
    
def clean_extracted_textOld(text):
    """
    Nettoie le texte extrait en supprimant les caractères bizarres
    et tous les sauts de ligne pour avoir un seul paragraphe
    """
    if not text:
        return ""
    
    # 1. Normaliser les caractères Unicode
    text = unicodedata.normalize('NFKC', text)
    
    # 2. Supprimer tous les sauts de ligne et retours chariot
    text = re.sub(r'[\n\r]+', ' ', text)
    
    # 3. Supprimer les caractères de contrôle et spéciaux
    # Garder lettres, chiffres, ponctuation basique, espaces
    text = re.sub(r'[^\w\s.,;:!?()\-/\@]', '', text)
    
    # 4. Remplacer les séquences de caractères bizarres spécifiques
    text = re.sub(r'•- - -', '---', text)
    text = re.sub(r'·1', 'Article 1', text)
    text = re.sub(r'·', '', text)
    text = re.sub(r'�', '', text)  # Supprimer les caractères de remplacement
    
    # 5. Corriger les espaces multiples pour avoir un espace unique entre les mots
    text = re.sub(r'\s+', ' ', text)
    
    # 6. Remplacer les virgules par des points-virgules dans certains contextes
    text = re.sub(r'(ARTICLE \d+),', r'\1;', text)
    
    return text.strip()


def clean_extracted_text_Old2(text):
    """
    Nettoie le texte extrait en supprimant les caractères bizarres,
    remplace les virgules par des points-virgules et formate le texte
    """
    if not text:
        return ""
    
    # 1. Normaliser les caractères Unicode
    text = unicodedata.normalize('NFKC', text)
    
    # 2. Supprimer tous les sauts de ligne et retours chariot
    text = re.sub(r'[\n\r]+', ' ', text)
    
    # 3. Remplacer les virgules par des points-virgules
    text = re.sub(r',', ';', text)
    
    # 4. Supprimer les caractères de contrôle et spéciaux
    # Garder lettres, chiffres, ponctuation basique, espaces
    text = re.sub(r'[^\w\s.;:!?()\-/\@]', '', text)
    
    # 5. Remplacer les séquences de caractères bizarres spécifiques
    text = re.sub(r'•- - -', '---', text)
    text = re.sub(r'·', '', text)
    text = re.sub(r'�', '', text)  # Supprimer les caractères de remplacement
    
    # 6. Nettoyer la ponctuation - espaces cohérents
    text = re.sub(r'\s+([.;:!?])', r'\1', text)  # Supprimer espace avant ponctuation
    text = re.sub(r'([.;:!?])\s+', r'\1 ', text)  # Un espace après ponctuation
    
    # 7. Corriger les espaces multiples pour avoir un espace unique entre les mots
    text = re.sub(r'\s+', ' ', text)
    
    # 8. Formater les titres et sections (ex: "1 LE PARDON" -> "1; LE PARDON")
    # text = re.sub(r'(\d+)\s+([A-Z])', r'\1; \2', text)
    
    # 9. Formater les références bibliques (ex: "Mt 18.21-35" -> "Mt 18;21-35")
    text = re.sub(r'([A-Za-z]+ \d+)\.(\d+)', r'\1;\2', text)
    
    # 10. Supprimer les espaces en début et fin
    text = text.strip()
    
    return text

def clean_extracted_text_Old3(text):
    """
    Version plus précise pour votre format spécifique
    """
    if not text:
        return ""
    
    # Normaliser
    text = unicodedata.normalize('NFKC', text)
    
    # Séparer en lignes
    lines = [line.strip() for line in text.split('\n') if line.strip()]
    
    # Identifier les types de lignes
    result_lines = []
    current_para = []
    
    for line in lines:
        # Lignes à garder séparées (courtes, titres, contacts)
        if (len(line) < 60 or 
            line.isupper() or
            any(keyword in line.lower() for keyword in ['tél', 'tel', 'email', 'objet', 'madame', 'monsieur']) or
            re.match(r'^[A-Z][a-z]+ [A-Z][a-z]+', line) or  # Noms propres
            re.match(r'^[A-Z\s]+, \d+', line)):  # "Ville, date"
            
            if current_para:
                result_lines.append(' '.join(current_para))
                current_para = []
            result_lines.append(line)
        else:
            # Lignes de paragraphe à regrouper
            current_para.append(line)
    
    # Dernier paragraphe
    if current_para:
        result_lines.append(' '.join(current_para))
    
    # Reconstituer avec sauts de ligne
    text = '\n'.join(result_lines)
    
    # Remplacer virgules
    text = text.replace(',', ';')
    
    return text

def clean_extracted_text(text):
    """
    Fonction simple pour extraire et regrouper le texte
    """
    if not text:
        return ""
    
    # Normaliser le texte
    text = unicodedata.normalize('NFKC', text)
    
    # Nettoyer les caractères spéciaux problématiques
    text = re.sub(r'[�\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', text)
    
    # Séparer en lignes et nettoyer
    lines = []
    for line in text.split('\n'):
        line = line.strip()
        if line:
            # Remplacer les virgules par des points-virgules
            line = line.replace(',', ';')
            # Nettoyer les caractères de fin de ligne
            line = re.sub(r'[;:-]+$', '', line)
            # Espaces multiples -> simple
            line = re.sub(r'\s+', ' ', line)
            lines.append(line)
    
    if not lines:
        return ""
    
    # Regroupement simple en paragraphes
    paragraphs = []
    current_para = []
    
    for line in lines:
        # Si la ligne est courte, considérer comme séparée
        if len(line) < 50:
            if current_para:
                paragraphs.append(' '.join(current_para))
                current_para = []
            paragraphs.append(line)
        else:
            # Ligne longue -> ajouter au paragraphe
            current_para.append(line)
    
    # Ajout