File size: 5,252 Bytes
3dc6c49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fb9658c
 
3dc6c49
 
 
 
 
 
fb9658c
 
 
d973914
 
 
 
 
 
 
 
fb9658c
d973914
 
fb9658c
d973914
 
 
fb9658c
d973914
 
fb9658c
d973914
3dc6c49
 
d973914
 
3dc6c49
d973914
 
3dc6c49
d973914
3dc6c49
 
fb9658c
3dc6c49
d973914
3dc6c49
 
 
 
 
 
 
4cc0fc9
3dc6c49
 
 
 
 
 
 
 
 
c43ad59
3e27b44
3dc6c49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fb9658c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#!/usr/bin/env python

import os
import re
import tempfile
from pathlib import Path

import pdfplumber
import docx
import gradio as gr

def clean_text_for_rag(text: str) -> str:
    """Normalise et nettoie le texte pour un usage RAG."""
    # Normalisation des caractères typographiques
    text = re.sub(
        r"[’‘“”«»–—\u00A0\u202F…œŒæÆ©®™§°±×÷]",
        lambda m: {
            "’": "'", "‘": "'", "“": '"', "”": '"',
            "«": '"', "»": '"', "–": "-", "—": "-",
            "…": "...", "œ": "oe", "Œ": "OE",
            "æ": "ae", "Æ": "AE", "©": "(c)", "®": "(R)",
            "™": "TM", "§": "§", "°": "°", "±": "+/-",
            "×": "x", "÷": "/"
        }.get(m.group(0), m.group(0)),
        text,
    )
    # Conserver uniquement les caractères suivants
    text = re.sub(r'[^a-zA-ZÀ-ÿæ-œ0-9\s\.\,\:\;\!\?\-\_\'\"\\\(\)]', '', text)
    # Réduire les espaces multiples
    return re.sub(r'\s+', ' ', text).strip()


def extract_and_clean_pdf(pdf_path: str) -> str:
    """Ouvre le PDF, récupère le texte et le nettoie."""
    print(f"[+] Extraction du PDF : {pdf_path}")
    all_pages = []
    with pdfplumber.open(pdf_path) as pdf:
        for page in pdf.pages:
            txt = page.extract_text()
            if txt:
                all_pages.append(txt)
    return clean_text_for_rag(" ".join(all_pages))


def extract_and_clean_docx(docx_path: str) -> str:
    """Lit un fichier DOCX et le nettoie."""
    print(f"[+] Extraction du DOCX : {docx_path}")
    doc = docx.Document(docx_path)
    paragraphs = []
    for para in doc.paragraphs:
        text = para.text.strip()
        if text:
            paragraphs.append(text)
    return clean_text_for_rag(" ".join(paragraphs))

def extract_and_clean_txt(txt_path: str) -> str:
    """Lit un fichier texte (txt, md, …) et le nettoie."""
    print(f"[+] Lecture du fichier texte : {txt_path}")
    with open(txt_path, "r", encoding="utf-8") as f:
        lines = f.readlines()
    cleaned = [
        clean_text_for_rag(line.strip())
        for line in lines
        if line.strip()
    ]
    return "\n".join(cleaned)

def process_file(input_file, output_name):

    """
    - Detecte le type (PDF ou texte)
    - Effectue l'extraction + nettoyage
    - Crée un fichier temporaire **avec le nom choisi** (output_name)
    - Retourne le chemin du fichier temporaire (Gradio le propose en téléchargement)
    """
    
    if input_file is None:
        return None
        
    if hasattr(input_file, "read"):
        data = input_file.read()
        filename = input_file.name
    elif isinstance(input_file, str):
        filename = input_file
        with open(input_file, "rb") as f:
            data = f.read()
    else:
        filename = input_file[0].name
        data = input_file[0].read()

    # écrire dans /tmp (important sur HF Spaces)
    suffix = os.path.splitext(filename)[1]
    tmp_path = os.path.join(tempfile.gettempdir(), "upload" + suffix)

    with open(tmp_path, "wb") as f:
        f.write(data)

    ext = suffix.lower()

    if ext == ".pdf":
        cleaned_text = extract_and_clean_pdf(tmp_path)

    elif ext == ".docx":
        cleaned_text = extract_and_clean_docx(tmp_path)

    else:
        cleaned_text = extract_and_clean_txt(tmp_path)

    if not output_name.lower().endswith(".md"):
        output_name += ".md"

    out_path = os.path.join(tempfile.gettempdir(), output_name)

    with open(out_path, "w", encoding="utf-8") as f:
        f.write(cleaned_text)

    return out_path

with gr.Blocks(title="Nettoyage de texte pour RAG") as demo:
    gr.Markdown("# 📄 Nettoyage d'un fichier pour optimisation de vos pipelines RAG")
    gr.Markdown(
        "Déposez simplement votre fichier : nous nous chargeons d’extraire son contenu textuel, de le nettoyer "
        "puis de vous le restituer en format markdown **sous le nom que vous choisissez.**"
    )

    with gr.Row():
        with gr.Column(scale=1):
            input_file = gr.File(
                label="Déposez votre fichier ici",
                file_types=[".pdf", ".txt", ".md", ".docx"],
                file_count="single",
            )
            output_name = gr.Textbox(
                value="output.md",
                label="Nom du fichier de sortie (en .md)",
                placeholder="exemple.md",
                interactive=True,
            )
            submit_btn = gr.Button("Traiter le fichier", variant="primary")
        with gr.Column(scale=1):
            output_file = gr.File(
                label="Fichier nettoyé (.md)",
                file_types=["md"],
            )

    submit_btn.click(
        fn=process_file,
        inputs=[input_file, output_name],
        outputs=output_file,
    )

    gr.Markdown(
        """
        ---
        **Prétraitements effectués :**
        - Suppression des symboles non imprimables et des caractères parasites  
        - Conservation des lettres (y compris accentuées), chiffres, espaces et ponctuation simple 
        - Normalisation des espaces pour un texte harmonieux  
        - Export automatique au format **`.md`**  
        
        """
    )

if __name__ == "__main__":
    demo.launch()