kebson commited on
Commit
7d8ddd9
·
verified ·
1 Parent(s): a3affb4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +93 -43
app.py CHANGED
@@ -1,63 +1,113 @@
1
  import gradio as gr
2
  import numpy as np
3
- from PIL import Image
4
- import pytesseract
5
 
6
- def extract_second_column(image):
 
 
 
 
 
7
  if image is None:
8
- return "Aucune image fournie"
9
 
10
- image = image.convert("RGB")
11
  img = np.array(image)
 
 
 
 
 
 
 
 
 
 
 
12
 
13
- # OCR avec positions
14
- data = pytesseract.image_to_data(
15
- img,
16
- output_type=pytesseract.Output.DICT,
17
- config="--psm 6"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  )
19
 
20
- words = []
21
- for i in range(len(data["text"])):
22
- text = data["text"][i].strip()
23
- if text:
24
- x = data["left"][i]
25
- y = data["top"][i]
26
- words.append((text, x, y))
 
 
 
 
 
 
 
 
 
27
 
28
- if not words:
29
- return "Aucun texte détecté"
 
 
 
30
 
31
- # Trier par X (colonnes)
32
- words.sort(key=lambda w: w[1])
 
 
 
 
33
 
34
- # Regrouper par colonnes
35
- columns = []
36
- for word in words:
37
- placed = False
38
- for col in columns:
39
- if abs(col[0][1] - word[1]) < 60:
40
- col.append(word)
41
- placed = True
42
- break
43
- if not placed:
44
- columns.append([word])
45
 
46
- if len(columns) < 2:
47
- return "Moins de 2 colonnes détectées"
48
 
49
- # 2ᵉ colonne
50
- second_column = sorted(columns[1], key=lambda w: w[2])
 
 
51
 
52
- return "\n".join([w[0] for w in second_column])
 
53
 
 
54
 
 
 
 
55
  demo = gr.Interface(
56
- fn=extract_second_column,
57
- inputs=gr.Image(type="pil"),
58
- outputs=gr.Textbox(lines=20),
59
- title="Extraction de la 2ᵉ colonne (Facture)",
60
- description="OCR + regroupement par colonnes (optimisé pour factures)"
61
  )
62
 
63
- demo.launch()
 
1
  import gradio as gr
2
  import numpy as np
3
+ from paddleocr import PaddleOCR
4
+ from sklearn.cluster import KMeans
5
 
6
+ ocr = PaddleOCR(
7
+ use_textline_orientation=True,
8
+ lang="fr"
9
+ )
10
+
11
+ def extract_column2_9_lines(image):
12
  if image is None:
13
+ return "Aucune image fournie."
14
 
 
15
  img = np.array(image)
16
+ result = ocr.predict(img)
17
+
18
+ if not result or len(result) == 0:
19
+ return "OCR exécuté mais aucun texte détecté."
20
+
21
+ data = result[0]
22
+ texts = data.get("rec_texts", [])
23
+ boxes = data.get("dt_polys", [])
24
+
25
+ if not texts:
26
+ return "Aucun texte exploitable détecté."
27
 
28
+ # -----------------------------
29
+ # 1. Collecte OCR
30
+ # -----------------------------
31
+ elements = []
32
+ for text, box in zip(texts, boxes):
33
+ text = text.strip()
34
+ if len(text) < 2:
35
+ continue
36
+ x_center = np.mean([p[0] for p in box])
37
+ y_center = np.mean([p[1] for p in box])
38
+ elements.append((x_center, y_center, text))
39
+
40
+ # -----------------------------
41
+ # 2. Clustering vertical (colonnes)
42
+ # -----------------------------
43
+ X = np.array([[e[0]] for e in elements])
44
+ n_cols = 6
45
+ kmeans = KMeans(n_clusters=n_cols, random_state=42).fit(X)
46
+ labels = kmeans.labels_
47
+
48
+ columns = {}
49
+ for (x, y, text), label in zip(elements, labels):
50
+ columns.setdefault(label, []).append((x, y, text))
51
+
52
+ sorted_columns = sorted(
53
+ columns.values(),
54
+ key=lambda col: np.mean([e[0] for e in col])
55
  )
56
 
57
+ if len(sorted_columns) < 2:
58
+ return "Impossible de détecter la colonne 2."
59
+
60
+ # -----------------------------
61
+ # 3. Sélection colonne 2
62
+ # -----------------------------
63
+ col = sorted_columns[1]
64
+ col.sort(key=lambda e: e[1]) # top → bottom
65
+
66
+ # -----------------------------
67
+ # 4. FUSION DES LIGNES OCR
68
+ # -----------------------------
69
+ merged_lines = []
70
+ current_text = ""
71
+ last_y = None
72
+ Y_THRESHOLD = 18
73
 
74
+ for _, y, text in col:
75
+ if text.upper().startswith((
76
+ "DESIGNATION", "UNITE", "QUANT", "PRIX", "TOTAL", "LOT"
77
+ )):
78
+ continue
79
 
80
+ if last_y is None or abs(y - last_y) > Y_THRESHOLD:
81
+ if current_text:
82
+ merged_lines.append(current_text.strip())
83
+ current_text = text
84
+ else:
85
+ current_text += " " + text
86
 
87
+ last_y = y
 
 
 
 
 
 
 
 
 
 
88
 
89
+ if current_text:
90
+ merged_lines.append(current_text.strip())
91
 
92
+ # -----------------------------
93
+ # 5. 9 premières lignes
94
+ # -----------------------------
95
+ final_lines = merged_lines[:9]
96
 
97
+ if not final_lines:
98
+ return "Colonne détectée mais lignes vides."
99
 
100
+ return "\n".join(final_lines)
101
 
102
+ # -----------------------------
103
+ # Interface Gradio
104
+ # -----------------------------
105
  demo = gr.Interface(
106
+ fn=extract_column2_9_lines,
107
+ inputs=gr.Image(type="pil", label="Image du devis"),
108
+ outputs=gr.Textbox(label="Colonne 2 – 9 premières lignes"),
109
+ title="Extraction de la colonne DESIGNATIONS",
110
+ description="Fusion automatique des lignes OCR (devis & tableaux)"
111
  )
112
 
113
+ demo.launch(server_name="0.0.0.0", server_port=7860)