NOBODY204 commited on
Commit
bc716f0
·
verified ·
1 Parent(s): e20eb2c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +105 -69
app.py CHANGED
@@ -1,83 +1,119 @@
1
  import gradio as gr
2
- import PyPDF2
3
  import torch
 
 
 
 
 
 
 
 
4
  from transformers import AutoTokenizer, AutoModelForCausalLM
5
 
 
6
  MODEL_NAME = "TinyLlama/TinyLlama-1.1B-Chat-v1.0"
 
 
 
7
 
8
- tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
9
-
10
- # Charger modèle sans device_map
11
- model = AutoModelForCausalLM.from_pretrained(
12
- MODEL_NAME
13
- )
14
 
 
15
  device = "cuda" if torch.cuda.is_available() else "cpu"
16
- model = model.to(device)
17
-
18
- def extract_text(pdf_file):
19
- if pdf_file is None:
20
- return ""
21
-
 
 
 
 
 
 
 
 
 
 
22
  try:
23
- reader = PyPDF2.PdfReader(pdf_file.name)
24
- text = ""
25
- for page in reader.pages:
26
- text += (page.extract_text() or "") + "\n"
 
 
 
 
 
 
 
27
  return text.strip()
28
  except Exception as e:
29
- return f"Erreur PDF: {str(e)}"
30
-
31
- def chat(message, history, pdf_file):
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  history = history or []
33
-
34
- pdf_text = extract_text(pdf_file)
35
- if not pdf_text.strip():
36
- pdf_text = "Aucun texte détecté dans le PDF."
37
-
38
- context = pdf_text[:2500]
39
-
40
- prompt = f"""
41
- Tu es ArchivChat.
42
- Réponds uniquement avec les informations du document.
43
-
44
- DOCUMENT:
45
- {context}
46
-
47
- QUESTION:
48
- {message}
49
-
50
- REPONSE:
51
- """
52
-
53
- inputs = tokenizer(prompt, return_tensors="pt").to(device)
54
-
55
  with torch.no_grad():
56
- output = model.generate(
57
- **inputs,
58
- max_new_tokens=200,
59
- do_sample=True,
60
- temperature=0.7,
61
- top_p=0.9
62
- )
63
-
64
- answer = tokenizer.decode(output[0], skip_special_tokens=True)
65
-
66
- if "REPONSE:" in answer:
67
- answer = answer.split("REPONSE:")[-1].strip()
68
-
69
- history.append((message, answer))
70
- return "", history
71
-
72
- with gr.Blocks() as demo:
73
- gr.Markdown("# 📁 ArchivChat (Sans clé API)")
74
-
75
  with gr.Row():
76
- pdf_file = gr.File(label="Uploader un PDF", file_types=[".pdf"])
77
- chatbot = gr.Chatbot()
78
-
79
- msg = gr.Textbox(label="Pose ta question")
80
- msg.submit(chat, [msg, chatbot, pdf_file], [msg, chatbot])
81
-
82
- demo.launch()
83
-
 
 
 
 
 
 
 
1
  import gradio as gr
 
2
  import torch
3
+ import os
4
+ import pytesseract
5
+ import cv2
6
+ import datetime
7
+ import shutil
8
+ from pdf2image import convert_from_path
9
+ from PIL import Image
10
+ from tqdm import tqdm
11
  from transformers import AutoTokenizer, AutoModelForCausalLM
12
 
13
+ # --- CONFIGURATION & MODÈLES ---
14
  MODEL_NAME = "TinyLlama/TinyLlama-1.1B-Chat-v1.0"
15
+ OCR_LANG = "fra+ara" # Support Français + Arabe
16
+ ARCHIVE_DIR = '/content/archive'
17
+ QR_DIR = '/content/processed_qrcodes'
18
 
19
+ os.makedirs(ARCHIVE_DIR, exist_ok=True)
20
+ os.makedirs(QR_DIR, exist_ok=True)
 
 
 
 
21
 
22
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
23
  device = "cuda" if torch.cuda.is_available() else "cpu"
24
+ model = AutoModelForCausalLM.from_pretrained(MODEL_NAME).to(device)
25
+
26
+ # --- POLITIQUES DE RÉTENTION ---
27
+ RETENTION_POLICY = {
28
+ "ressources humaines": {"active": 5, "semi": 10, "archived": float('inf')},
29
+ "facture": {"active": 7, "semi": 3, "archived": float('inf')},
30
+ "certificat medicale": {"active": 2, "semi": 0, "archived": float('inf')},
31
+ "autre": {"active": 1, "semi": 0, "archived": float('inf')}
32
+ }
33
+
34
+ # --- FONCTIONS OCR & CLASSIFICATION ---
35
+
36
+ def extract_text_advanced(file_path):
37
+ """Extraction OCR optimisée pour PDF scannés (Français/Arabe)."""
38
+ if not file_path: return ""
39
+ text = ""
40
  try:
41
+ # Conversion PDF en images haute résolution pour l'OCR
42
+ pages = convert_from_path(file_path, dpi=400)
43
+ for i, page in enumerate(pages):
44
+ img_path = f"/tmp/page_{i}.png"
45
+ page.save(img_path, "PNG")
46
+ img = cv2.imread(img_path)
47
+ # Prétraitement de l'image pour améliorer la lecture
48
+ gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
49
+ gray = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
50
+ text += pytesseract.image_to_string(gray, lang=OCR_LANG) + "\n"
51
+ os.remove(img_path)
52
  return text.strip()
53
  except Exception as e:
54
+ return f"Erreur OCR: {str(e)}"
55
+
56
+ def classify_doc(text):
57
+ """Classification automatique basée sur les mots-clés."""
58
+ text_lower = text.lower()
59
+ if "certificat médical" in text_lower or "منحة مرض" in text_lower:
60
+ return "certificat medicale"
61
+ elif "facture" in text_lower:
62
+ return "facture"
63
+ elif "ressources humaines" in text_lower or "rh" in text_lower:
64
+ return "ressources humaines"
65
+ return "autre"
66
+
67
+ # --- LOGIQUE DE CHAT ---
68
+
69
+ def chat_interface(message, history, pdf_file):
70
  history = history or []
71
+ pdf_text = extract_text_advanced(pdf_file.name) if pdf_file else ""
72
+ category = classify_doc(pdf_text)
73
+
74
+ # Instructions personnalisées (AI Covers & Radio) + Contexte document
75
+ system_prompt = (
76
+ "Tu es ArchivChat. Tu es expert en Radio et AI Covers. "
77
+ f"Document analysé (Catégorie: {category}). "
78
+ "Réponds en priorité selon le DOCUMENT. Si absent, utilise tes connaissances AI/Radio."
79
+ )
80
+
81
+ context = pdf_text[:2000]
82
+ full_prompt = f"<|system|>\n{system_prompt}\nDOC:{context}</s>\n"
83
+ for h in history:
84
+ full_prompt += f"<|user|>\n{h[0]}</s>\n<|assistant|>\n{h[1]}</s>\n"
85
+ full_prompt += f"<|user|>\n{message}</s>\n<|assistant|>\n"
86
+
87
+ inputs = tokenizer(full_prompt, return_tensors="pt").to(device)
 
 
 
 
 
88
  with torch.no_grad():
89
+ output = model.generate(**inputs, max_new_tokens=200, temperature=0.7)
90
+
91
+ response = tokenizer.decode(output[0], skip_special_tokens=True).split("<|assistant|>")[-1].strip()
92
+ history.append((message, response))
93
+
94
+ # Déplacement automatique vers l'archive après traitement
95
+ if pdf_file:
96
+ dest = os.path.join(ARCHIVE_DIR, os.path.basename(pdf_file.name))
97
+ shutil.copy(pdf_file.name, dest)
98
+
99
+ return "", history, f"Catégorie détectée : {category.upper()}"
100
+
101
+ # --- INTERFACE GRADIO ---
102
+
103
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
104
+ gr.Markdown("# 📁 ArchivChat & OCR Pro")
 
 
 
105
  with gr.Row():
106
+ with gr.Column(scale=1):
107
+ file_input = gr.File(label="Uploader PDF/Image")
108
+ status_label = gr.Label(label="Analyse Document")
109
+ with gr.Column(scale=2):
110
+ chatbot = gr.Chatbot(height=450)
111
+ msg = gr.Textbox(label="Question", placeholder="Posez une question sur le document ou sur la radio/AI covers...")
112
+ clear = gr.Button("Effacer")
113
+
114
+ msg.submit(chat_interface, [msg, chatbot, file_input], [msg, chatbot, status_label])
115
+ clear.click(lambda: None, None, chatbot, queue=False)
116
+
117
+ if __name__ == "__main__":
118
+ # Note : Nécessite l'installation système : apt install tesseract-ocr-fra tesseract-ocr-ara poppler-utils
119
+ demo.launch(debug=True)