Maria Tsilimos commited on
Commit
9e2b7c9
·
unverified ·
1 Parent(s): 5819fed

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +216 -206
app.py CHANGED
@@ -6,161 +6,99 @@ from transformers import pipeline
6
  import plotly.express as px
7
  import time
8
  import io
9
- import os
10
- from comet_ml import Experiment
11
  import zipfile
12
  import re
13
  from streamlit_extras.stylable_container import stylable_container
 
14
 
15
-
16
- st.set_page_config(layout="wide", page_title="Named Entity Recognition App")
17
-
18
-
19
-
20
 
21
  COMET_API_KEY = os.environ.get("COMET_API_KEY")
22
  COMET_WORKSPACE = os.environ.get("COMET_WORKSPACE")
23
  COMET_PROJECT_NAME = os.environ.get("COMET_PROJECT_NAME")
24
-
25
  comet_initialized = False
26
  if COMET_API_KEY and COMET_WORKSPACE and COMET_PROJECT_NAME:
27
  comet_initialized = True
28
 
29
-
30
-
31
- st.subheader("58-Italian Named Entity Recognition Web App", divider="rainbow")
32
  st.link_button("by nlpblogs", "https://nlpblogs.com", type="tertiary")
33
 
34
- expander = st.expander("**Important notes on the 58-Italian-Named Entity Recognition Web App**")
35
  expander.write('''
 
36
 
37
- **Named Entities:**
38
- This 58-Italian-Named Entity Recognition Web App predicts fifty-eight (58) labels
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
- ("**INDIRIZZO**: Identifica un indirizzo fisico.
41
-
42
- **VALUTA**: Rappresenta una valuta.
43
-
44
- **CVV**: Codice di sicurezza della carta di credito.
45
-
46
- **NUMERO_CONTO**: Numero di un conto bancario.
47
-
48
- **BIC**: Codice identificativo di una banca (Bank Identifier Code).
49
-
50
- **IBAN**: Numero di conto bancario internazionale.
51
-
52
- **STATO**: Identifica un paese o una nazione.
53
-
54
- **NOME**: Riferito al nome di una persona.
55
-
56
- **COGNOME**: Riferito al cognome di una persona.
57
-
58
- **CODICE_POSTALE**: Codice postale di un'area geografica.
59
-
60
- **IP**: Indirizzo IP di un dispositivo in rete.
61
-
62
- **ORARIO**: Riferito a un orario specifico.
63
-
64
- **URL**: Indirizzo web (Uniform Resource Locator).
65
-
66
- **LUOGO**: Identifica un luogo geografico.
67
-
68
- **IMPORTO**: Riferito a una somma di denaro.
69
-
70
- **EMAIL**: Indirizzo di posta elettronica.
71
-
72
- **PASSWORD**: Parola chiave per l'accesso a sistemi protetti.
73
-
74
- **NUMERO_CARTA**: Numero di una carta di credito o debito.
75
-
76
- **TARGA_VEICOLO**: Numero di targa di un veicolo.
77
-
78
- **DATA_NASCITA**: Data di nascita di una persona.
79
-
80
- **DATA_MORTE**: Data di decesso di una persona.
81
-
82
- **RAGIONE_SOCIALE**: Nome legale di un'azienda o entità commerciale.
83
-
84
- **ETA**: Età di una persona.
85
-
86
- **DATA**: Riferita a una data generica.
87
-
88
- **PROFESSIONE**: Occupazione o lavoro di una persona.
89
-
90
- **PIN**: Numero di identificazione personale.
91
-
92
- **NUMERO_TELEFONO**: Numero telefonico.
93
-
94
- **FOGLIO**: Riferito a un foglio di documentazione.
95
-
96
- **PARTICELLA**: Riferito a una particella catastale.
97
-
98
- **CARTELLA_CLINICA**: Documentazione medica di un paziente.
99
-
100
- **MALATTIA**: Identifica una malattia o condizione medica.
101
-
102
- **MEDICINA**: Riferito a un farmaco o trattamento medico.
103
-
104
- **CODICE_FISCALE**: Codice fiscale personale o aziendale.
105
-
106
- **NUMERO_DOCUMENTO**: Numero di un documento ufficiale.
107
-
108
- **STORIA_CLINICA**: Registro delle condizioni mediche di un paziente.
109
-
110
- **AVV_NOTAIO**: Identifica un avvocato o notaio.
111
-
112
- **P_IVA**: Partita IVA di un'azienda o professionista.
113
-
114
- **LEGGE**: Riferito a una legge specifica.
115
-
116
- **TASSO_MUTUO**: Tasso di interesse di un mutuo.
117
-
118
- **N_SENTENZA**: Numero di una sentenza legale.
119
-
120
- **MAPPALE**: Riferito a un mappale catastale.
121
-
122
- **SUBALTERNO**: Riferito a un subalterno catastale.
123
-
124
- **REGIME_PATRIMONIALE**: Stato patrimoniale in ambito legale.
125
-
126
- **STATO_CIVILE**: Stato civile di una persona.
127
-
128
- **BANCA**: Identifica una banca o istituto di credito.
129
-
130
- **BRAND**: Marchio o brand commerciale.
131
-
132
- **NUM_ASSEGNO_BANCARIO**: Numero di un assegno bancario.
133
-
134
- **IMEI**: Numero di identificazione internazionale di un dispositivo mobile.
135
-
136
- **N_LICENZA**: Numero di una licenza specifica.
137
-
138
- **IPV6_1**: Indirizzo IP versione 6.
139
-
140
- **MAC**: Indirizzo MAC di un dispositivo di rete.
141
-
142
- **USER_AGENT**: Identifica il software usato per accedere a una rete.
143
-
144
- **TRIBUNALE**: Identifica un tribunale specifico.
145
-
146
- **STRENGTH**: Riferito alla forza o intensità di del medicinale.
147
-
148
- **FREQUENZA**: Riferito alla frequenza di un trattamento medico.
149
-
150
- **DURATION**: Durata di un evento o trattamento.
151
-
152
- **DOSAGGIO**: Quantità di un medicinale da assumere.
153
-
154
- **FORM**: Forma del medicinale, ad esempio compresse").
155
-
156
- Results are presented in an easy-to-read table, visualized in an interactive tree map, pie chart, and bar chart, and are available for download along with a Glossary of tags.
157
 
158
  **How to Use:**
159
  Paste a URL, and then press Enter. If you type or paste text, just press Ctrl + Enter.
160
 
161
  **Usage Limits:**
162
- You can request results up to 10 times.
163
-
 
 
 
164
  **Customization:**
165
  To change the app's background color to white or black, click the three-dot menu on the right-hand side of your app, go to Settings and then Choose app theme, colors and fonts.
166
 
@@ -168,43 +106,32 @@ expander.write('''
168
  If your connection times out, please refresh the page or reopen the app's URL.
169
 
170
  For any errors or inquiries, please contact us at [email protected]
171
-
172
- ''')
173
-
174
-
175
-
176
-
177
-
178
 
179
  with st.sidebar:
180
  container = st.container(border=True)
181
  container.write("**Named Entity Recognition (NER)** is the task of extracting and tagging entities in text data. Entities can be persons, organizations, locations, countries, products, events etc.")
182
  st.subheader("Related NLP Web Apps", divider="rainbow")
183
- st.link_button("8-Named Entity Recognition Web App", "https://nlpblogs.com/shop/named-entity-recognition-ner/8-named-entity-recognition-web-app/", type="primary")
184
-
185
 
186
  if 'source_type_attempts' not in st.session_state:
187
  st.session_state['source_type_attempts'] = 0
188
- max_attempts = 10
189
 
190
  def clear_url_input():
191
-
192
  st.session_state.url = ""
193
 
194
  def clear_text_input():
195
-
196
  st.session_state.my_text_area = ""
197
 
198
  url = st.text_input("Enter URL from the internet, and then press Enter:", key="url")
199
  st.button("Clear URL", on_click=clear_url_input)
200
-
201
  text = st.text_area("Type or paste your text below, and then press Ctrl + Enter", key='my_text_area')
202
  st.button("Clear Text", on_click=clear_text_input)
203
 
204
-
205
  source_type = None
206
  input_content = None
207
- text_to_process = None
208
 
209
  if url:
210
  source_type = 'url'
@@ -214,25 +141,22 @@ elif text:
214
  input_content = text
215
 
216
  if source_type:
217
-
218
  st.subheader("Results", divider = "rainbow")
219
 
220
-
221
  if st.session_state['source_type_attempts'] >= max_attempts:
222
  st.error(f"You have requested results {max_attempts} times. You have reached your daily request limit.")
223
  st.stop()
224
-
225
  st.session_state['source_type_attempts'] += 1
226
-
227
 
228
  @st.cache_resource
229
  def load_ner_model():
230
-
231
  return pipeline("token-classification", model="DeepMount00/Italian_NER_XXL", aggregation_strategy="max")
232
-
233
  model = load_ner_model()
234
- experiment = None
235
-
236
  try:
237
  if source_type == 'url':
238
  if not url.startswith(("http://", "https://")):
@@ -246,17 +170,13 @@ if source_type:
246
  st.divider()
247
  st.write("**Input text content**")
248
  st.write(text_to_process[:500] + "..." if len(text_to_process) > 500 else text_to_process)
249
-
250
-
251
-
252
  elif source_type == 'text':
253
  text_to_process = text
254
  st.divider()
255
  st.write("**Input text content**")
256
-
257
  st.write(text_to_process[:500] + "..." if len(text_to_process) > 500 else text_to_process)
258
-
259
- if text_to_process and len(text_to_process.strip()) > 0:
260
  with st.spinner("Analyzing text...", show_time=True):
261
  entities = model(text_to_process)
262
  data = []
@@ -269,14 +189,12 @@ if source_type:
269
  'end': entity['end']
270
  })
271
  df = pd.DataFrame(data)
272
-
273
 
274
  pattern = r'[^\w\s]'
275
  df['word'] = df['word'].replace(pattern, '', regex=True)
276
 
277
  df = df.replace('', 'Unknown')
278
- st.dataframe(df)
279
-
280
 
281
  if comet_initialized:
282
  experiment = Experiment(
@@ -287,40 +205,131 @@ if source_type:
287
  experiment.log_parameter("input_source_type", source_type)
288
  experiment.log_parameter("input_content_length", len(input_content))
289
  experiment.log_table("predicted_entities", df)
290
-
291
  with st.expander("See Glossary of tags"):
292
  st.write('''
293
  '**word**': ['entity extracted from your text data']
294
 
295
  '**score**': ['accuracy score; how accurately a tag has been assigned to a given entity']
296
-
297
  '**entity_group**': ['label (tag) assigned to a given extracted entity']
298
-
299
  '**start**': ['index of the start of the corresponding entity']
300
-
301
- '**end**': ['index of the end of the corresponding entity']
302
 
 
303
  ''')
304
 
305
-
306
  if not df.empty:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
 
308
- st.markdown("---")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
309
  st.subheader("Treemap", divider="rainbow")
310
  fig = px.treemap(df, path=[px.Constant("all"), 'entity_group', 'word'],
311
  values='score', color='entity_group',
312
  )
313
  fig.update_layout(margin=dict(t=50, l=25, r=25, b=25))
314
  st.plotly_chart(fig, use_container_width=True)
315
- if comet_initialized and experiment:
316
- experiment.log_figure(figure=fig, figure_name="entity_treemap")
317
-
318
 
 
 
319
 
320
  value_counts = df['entity_group'].value_counts().reset_index()
321
  value_counts.columns = ['entity_group', 'count']
322
-
323
  col1, col2 = st.columns(2)
 
324
  with col1:
325
  st.subheader("Pie Chart", divider="rainbow")
326
  fig1 = px.pie(value_counts, values='count', names='entity_group',
@@ -328,59 +337,60 @@ if source_type:
328
  title='Percentage of Predicted Labels')
329
  fig1.update_traces(textposition='inside', textinfo='percent+label')
330
  st.plotly_chart(fig1, use_container_width=True)
331
- if comet_initialized and experiment: # Check if experiment is initialized
 
332
  experiment.log_figure(figure=fig1, figure_name="label_pie_chart")
333
-
334
  with col2:
335
  st.subheader("Bar Chart", divider="rainbow")
336
  fig2 = px.bar(value_counts, x="count", y="entity_group", color="entity_group",
337
  text_auto=True, title='Occurrences of Predicted Labels')
338
  st.plotly_chart(fig2, use_container_width=True)
339
- if comet_initialized and experiment: # Check if experiment is initialized
 
340
  experiment.log_figure(figure=fig2, figure_name="label_bar_chart")
341
- else:
342
  st.warning("No entities were extracted from the provided text.")
343
-
344
-
345
 
346
  dfa = pd.DataFrame(
347
  data={
348
- 'word': ['entity extracted from your text data'],
349
- 'score': ['accuracy score; how accurately a tag has been assigned to a given entity'],
350
- 'entity_group': ['label (tag) assigned to a given extracted entity'],
351
- 'start': ['index of the start of the corresponding entity'],
352
- 'end': ['index of the end of the corresponding entity'],
353
-
354
-
 
355
  }
356
  )
 
357
  buf = io.BytesIO()
358
  with zipfile.ZipFile(buf, "w") as myzip:
359
- if not df.empty:
360
  myzip.writestr("Summary_of_results.csv", df.to_csv(index=False))
361
  myzip.writestr("Glossary_of_tags.csv", dfa.to_csv(index=False))
362
-
363
  with stylable_container(
364
- key="download_button",
365
- css_styles="""button { background-color: yellow; border: 1px solid black; padding: 5px; color: black; }""",
366
- ):
367
  st.download_button(
368
- label="Download zip file",
369
- data=buf.getvalue(),
370
- file_name="nlpblogs_ner_results.zip",
371
- mime="application/zip",)
372
-
373
-
374
-
375
  st.divider()
376
- else:
377
  st.warning("No meaningful text found to process. Please enter a URL or text.")
378
-
379
-
380
  except Exception as e:
381
  st.error(f"An unexpected error occurred: {e}")
382
  finally:
383
  if comet_initialized and experiment:
384
  experiment.end()
385
-
386
- st.write(f"Number of times you requested results: **{st.session_state['source_type_attempts']}/{max_attempts}**")
 
 
 
 
6
  import plotly.express as px
7
  import time
8
  import io
9
+ import os
10
+ from comet_ml import Experiment
11
  import zipfile
12
  import re
13
  from streamlit_extras.stylable_container import stylable_container
14
+ import numpy as np # Import numpy for np.nan
15
 
16
+ st.set_page_config(layout="wide", page_title="Italian TXT & URL Entity Finder")
 
 
 
 
17
 
18
  COMET_API_KEY = os.environ.get("COMET_API_KEY")
19
  COMET_WORKSPACE = os.environ.get("COMET_WORKSPACE")
20
  COMET_PROJECT_NAME = os.environ.get("COMET_PROJECT_NAME")
 
21
  comet_initialized = False
22
  if COMET_API_KEY and COMET_WORKSPACE and COMET_PROJECT_NAME:
23
  comet_initialized = True
24
 
25
+ st.subheader("Italian TXT & URL Entity Finder", divider="rainbow")
 
 
26
  st.link_button("by nlpblogs", "https://nlpblogs.com", type="tertiary")
27
 
28
+ expander = st.expander("**Important notes on the Italian TXT & URL Entity Finder**")
29
  expander.write('''
30
+ **Named Entities:** This Italian TXT & URL Entity Finder predicts fifty-eight (58) labels:
31
 
32
+ **INDIRIZZO**: Identifica un indirizzo fisico.
33
+ **VALUTA**: Rappresenta una valuta.
34
+ **CVV**: Codice di sicurezza della carta di credito.
35
+ **NUMERO_CONTO**: Numero di un conto bancario.
36
+ **BIC**: Codice identificativo di una banca (Bank Identifier Code).
37
+ **IBAN**: Numero di conto bancario internazionale.
38
+ **STATO**: Identifica un paese o una nazione.
39
+ **NOME**: Riferito al nome di una persona.
40
+ **COGNOME**: Riferito al cognome di una persona.
41
+ **CODICE_POSTALE**: Codice postale di un'area geografica.
42
+ **IP**: Indirizzo IP di un dispositivo in rete.
43
+ **ORARIO**: Riferito a un orario specifico.
44
+ **URL**: Indirizzo web (Uniform Resource Locator).
45
+ **LUOGO**: Identifica un luogo geografico.
46
+ **IMPORTO**: Riferito a una somma di denaro.
47
+ **EMAIL**: Indirizzo di posta elettronica.
48
+ **PASSWORD**: Parola chiave per l'accesso a sistemi protetti.
49
+ **NUMERO_CARTA**: Numero di una carta di credito o debito.
50
+ **TARGA_VEICOLO**: Numero di targa di un veicolo.
51
+ **DATA_NASCITA**: Data di nascita di una persona.
52
+ **DATA_MORTE**: Data di decesso di una persona.
53
+ **RAGIONE_SOCIALE**: Nome legale di un'azienda o entità commerciale.
54
+ **ETA**: Età di una persona.
55
+ **DATA**: Riferita a una data generica.
56
+ **PROFESSIONE**: Occupazione o lavoro di una persona.
57
+ **PIN**: Numero di identificazione personale.
58
+ **NUMERO_TELEFONO**: Numero telefonico.
59
+ **FOGLIO**: Riferito a un foglio di documentazione.
60
+ **PARTICELLA**: Riferito a una particella catastale.
61
+ **CARTELLA_CLINICA**: Documentazione medica di un paziente.
62
+ **MALATTIA**: Identifica una malattia o condizione medica.
63
+ **MEDICINA**: Riferito a un farmaco o trattamento medico.
64
+ **CODICE_FISCALE**: Codice fiscale personale o aziendale.
65
+ **NUMERO_DOCUMENTO**: Numero di un documento ufficiale.
66
+ **STORIA_CLINICA**: Registro delle condizioni mediche di un paziente.
67
+ **AVV_NOTAIO**: Identifica un avvocato o notaio.
68
+ **P_IVA**: Partita IVA di un'azienda o professionista.
69
+ **LEGGE**: Riferito a una legge specifica.
70
+ **TASSO_MUTUO**: Tasso di interesse di un mutuo.
71
+ **N_SENTENZA**: Numero di una sentenza legale.
72
+ **MAPPALE**: Riferito a un mappale catastale.
73
+ **SUBALTERNO**: Riferito a un subalterno catastale.
74
+ **REGIME_PATRIMONIALE**: Stato patrimoniale in ambito legale.
75
+ **STATO_CIVILE**: Stato civile di una persona.
76
+ **BANCA**: Identifica una banca o istituto di credito.
77
+ **BRAND**: Marchio o brand commerciale.
78
+ **NUM_ASSEGNO_BANCARIO**: Numero di un assegno bancario.
79
+ **IMEI**: Numero di identificazione internazionale di un dispositivo mobile.
80
+ **N_LICENZA**: Numero di una licenza specifica.
81
+ **IPV6_1**: Indirizzo IP Versione 6.
82
+ **MAC**: Indirizzo MAC di un dispositivo di rete.
83
+ **USER_AGENT**: Identifica il software usato per accedere a una rete.
84
+ **TRIBUNALE**: Identifica un tribunale specifico.
85
+ **STRENGTH**: Riferito alla forza o intensità di del medicinale.
86
+ **FREQUENZA**: Riferito alla frequenza di un trattamento medico.
87
+ **DURATION**: Durata di un evento o trattamento.
88
+ **DOSAGGIO**: Quantità di un medicinale da assumere.
89
+ **FORM**: Forma del medicinale, ad esempio compresse.
90
 
91
+ Results are presented in an easy-to-read table, visualized in an interactive tree map, pie chart, and bar chart, and are available for download along with a Glossary of tags.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
  **How to Use:**
94
  Paste a URL, and then press Enter. If you type or paste text, just press Ctrl + Enter.
95
 
96
  **Usage Limits:**
97
+ You can request results up to 10 times.
98
+
99
+ **Language settings:**
100
+ Please check and adjust the language settings in your computer, so the Italian characters are handled properly in your downloaded file.
101
+
102
  **Customization:**
103
  To change the app's background color to white or black, click the three-dot menu on the right-hand side of your app, go to Settings and then Choose app theme, colors and fonts.
104
 
 
106
  If your connection times out, please refresh the page or reopen the app's URL.
107
 
108
  For any errors or inquiries, please contact us at [email protected]
109
+ ''')
 
 
 
 
 
 
110
 
111
  with st.sidebar:
112
  container = st.container(border=True)
113
  container.write("**Named Entity Recognition (NER)** is the task of extracting and tagging entities in text data. Entities can be persons, organizations, locations, countries, products, events etc.")
114
  st.subheader("Related NLP Web Apps", divider="rainbow")
115
+ st.link_button("English HTML Entity Finder", "https://nlpblogs.com/shop/named-entity-recognition-ner/english-html-entity-finder/", type="primary")
 
116
 
117
  if 'source_type_attempts' not in st.session_state:
118
  st.session_state['source_type_attempts'] = 0
119
+ max_attempts = 10
120
 
121
  def clear_url_input():
 
122
  st.session_state.url = ""
123
 
124
  def clear_text_input():
 
125
  st.session_state.my_text_area = ""
126
 
127
  url = st.text_input("Enter URL from the internet, and then press Enter:", key="url")
128
  st.button("Clear URL", on_click=clear_url_input)
 
129
  text = st.text_area("Type or paste your text below, and then press Ctrl + Enter", key='my_text_area')
130
  st.button("Clear Text", on_click=clear_text_input)
131
 
 
132
  source_type = None
133
  input_content = None
134
+ text_to_process = None
135
 
136
  if url:
137
  source_type = 'url'
 
141
  input_content = text
142
 
143
  if source_type:
144
+ start_time = time.time() # Start timer here
145
  st.subheader("Results", divider = "rainbow")
146
 
 
147
  if st.session_state['source_type_attempts'] >= max_attempts:
148
  st.error(f"You have requested results {max_attempts} times. You have reached your daily request limit.")
149
  st.stop()
150
+
151
  st.session_state['source_type_attempts'] += 1
 
152
 
153
  @st.cache_resource
154
  def load_ner_model():
 
155
  return pipeline("token-classification", model="DeepMount00/Italian_NER_XXL", aggregation_strategy="max")
156
+
157
  model = load_ner_model()
158
+ experiment = None
159
+
160
  try:
161
  if source_type == 'url':
162
  if not url.startswith(("http://", "https://")):
 
170
  st.divider()
171
  st.write("**Input text content**")
172
  st.write(text_to_process[:500] + "..." if len(text_to_process) > 500 else text_to_process)
 
 
 
173
  elif source_type == 'text':
174
  text_to_process = text
175
  st.divider()
176
  st.write("**Input text content**")
 
177
  st.write(text_to_process[:500] + "..." if len(text_to_process) > 500 else text_to_process)
178
+
179
+ if text_to_process and len(text_to_process.strip()) > 0:
180
  with st.spinner("Analyzing text...", show_time=True):
181
  entities = model(text_to_process)
182
  data = []
 
189
  'end': entity['end']
190
  })
191
  df = pd.DataFrame(data)
 
192
 
193
  pattern = r'[^\w\s]'
194
  df['word'] = df['word'].replace(pattern, '', regex=True)
195
 
196
  df = df.replace('', 'Unknown')
197
+ st.dataframe(df) # This is the full dataframe of all entities
 
198
 
199
  if comet_initialized:
200
  experiment = Experiment(
 
205
  experiment.log_parameter("input_source_type", source_type)
206
  experiment.log_parameter("input_content_length", len(input_content))
207
  experiment.log_table("predicted_entities", df)
208
+
209
  with st.expander("See Glossary of tags"):
210
  st.write('''
211
  '**word**': ['entity extracted from your text data']
212
 
213
  '**score**': ['accuracy score; how accurately a tag has been assigned to a given entity']
214
+
215
  '**entity_group**': ['label (tag) assigned to a given extracted entity']
216
+
217
  '**start**': ['index of the start of the corresponding entity']
 
 
218
 
219
+ '**end**': ['index of the end of the corresponding entity']
220
  ''')
221
 
 
222
  if not df.empty:
223
+ # --- NEW GROUPED ENTITIES SECTION - MOVED HERE ---
224
+ st.markdown("---") # Add a separator before the new section
225
+ st.subheader("Grouped Entities", divider = "blue")
226
+
227
+ # Define all 58 entity groups and their descriptions
228
+ entity_groups = {
229
+ "INDIRIZZO": "Indirizzo Fisico",
230
+ "VALUTA": "Valuta",
231
+ "CVV": "Codice di Sicurezza (CVV)",
232
+ "NUMERO_CONTO": "Numero Conto Bancario",
233
+ "BIC": "Codice Identificativo Banca (BIC)",
234
+ "IBAN": "Numero IBAN Internazionale",
235
+ "STATO": "Paese o Nazione",
236
+ "NOME": "Nome Persona",
237
+ "COGNOME": "Cognome Persona",
238
+ "CODICE_POSTALE": "Codice Postale",
239
+ "IP": "Indirizzo IP",
240
+ "ORARIO": "Orario Specifico",
241
+ "URL": "Indirizzo Web (URL)",
242
+ "LUOGO": "Luogo Geografico",
243
+ "IMPORTO": "Somma di Denaro",
244
+ "EMAIL": "Indirizzo Email",
245
+ "PASSWORD": "Parola Chiave (Password)",
246
+ "NUMERO_CARTA": "Numero Carta di Credito/Debito",
247
+ "TARGA_VEICOLO": "Numero Targa Veicolo",
248
+ "DATA_NASCITA": "Data di Nascita",
249
+ "DATA_MORTE": "Data di Decesso",
250
+ "RAGIONE_SOCIALE": "Nome Legale Azienda",
251
+ "ETA": "Età Persona",
252
+ "DATA": "Data Generica",
253
+ "PROFESSIONE": "Occupazione/Lavoro",
254
+ "PIN": "Numero PIN",
255
+ "NUMERO_TELEFONO": "Numero Telefonico",
256
+ "FOGLIO": "Foglio Documentazione",
257
+ "PARTICELLA": "Particella Catastale",
258
+ "CARTELLA_CLINICA": "Documentazione Medica Paziente",
259
+ "MALATTIA": "Malattia o Condizione Medica",
260
+ "MEDICINA": "Farmaco o Trattamento Medico",
261
+ "CODICE_FISCALE": "Codice Fiscale",
262
+ "NUMERO_DOCUMENTO": "Numero Documento Ufficiale",
263
+ "STORIA_CLINICA": "Registro Condizioni Mediche",
264
+ "AVV_NOTAIO": "Avvocato o Notaio",
265
+ "P_IVA": "Partita IVA",
266
+ "LEGGE": "Legge Specifica",
267
+ "TASSO_MUTUO": "Tasso di Interesse Mutuo",
268
+ "N_SENTENZA": "Numero Sentenza Legale",
269
+ "MAPPALE": "Mappale Catastale",
270
+ "SUBALTERNO": "Subalterno Catastale",
271
+ "REGIME_PATRIMONIALE": "Stato Patrimoniale Legale",
272
+ "STATO_CIVILE": "Stato Civile Persona",
273
+ "BANCA": "Banca/Istituto Credito",
274
+ "BRAND": "Marchio Commerciale",
275
+ "NUM_ASSEGNO_BANCARIO": "Numero Assegno Bancario",
276
+ "IMEI": "Numero IMEI Dispositivo Mobile",
277
+ "N_LICENZA": "Numero Licenza Specifica",
278
+ "IPV6_1": "Indirizzo IP Versione 6",
279
+ "MAC": "Indirizzo MAC Dispositivo Rete",
280
+ "USER_AGENT": "Software Accesso Rete",
281
+ "TRIBUNALE": "Tribunale Specifico",
282
+ "STRENGTH": "Forza/Intensità Medicinali",
283
+ "FREQUENZA": "Frequenza Trattamento Medico",
284
+ "DURATION": "Durata Evento/Trattamento",
285
+ "DOSAGGIO": "Quantità Medicinali",
286
+ "FORM": "Forma Medicinali"
287
+ }
288
 
289
+ # Convert entity_groups dictionary to a list of (key, title) tuples
290
+ entity_items = list(entity_groups.items())
291
+
292
+ # Define how many tabs per row
293
+ tabs_per_row = 5
294
+
295
+ # Loop through the entity items in chunks
296
+ for i in range(0, len(entity_items), tabs_per_row):
297
+ current_row_entities = entity_items[i : i + tabs_per_row]
298
+ tab_titles = [item[1] for item in current_row_entities]
299
+
300
+ tabs = st.tabs(tab_titles)
301
+ for j, (entity_group_key, tab_title) in enumerate(current_row_entities):
302
+ with tabs[j]:
303
+ if entity_group_key in df["entity_group"].unique():
304
+ df_filtered = df[df["entity_group"] == entity_group_key]
305
+ st.dataframe(df_filtered, use_container_width=True)
306
+ else:
307
+ st.info(f"No '{tab_title}' entities found in the text.")
308
+ # Display an empty DataFrame with column names
309
+ st.dataframe(pd.DataFrame({
310
+ 'word': [],
311
+ 'entity_group': [],
312
+ 'score': [],
313
+ 'start': [],
314
+ 'end': []
315
+ }), hide_index=True)
316
+ st.divider() # Divider after grouped entities section
317
+
318
+ # --- VISUALIZATIONS - NOW APPEAR AFTER GROUPED ENTITIES ---
319
  st.subheader("Treemap", divider="rainbow")
320
  fig = px.treemap(df, path=[px.Constant("all"), 'entity_group', 'word'],
321
  values='score', color='entity_group',
322
  )
323
  fig.update_layout(margin=dict(t=50, l=25, r=25, b=25))
324
  st.plotly_chart(fig, use_container_width=True)
 
 
 
325
 
326
+ if comet_initialized and experiment:
327
+ experiment.log_figure(figure=fig, figure_name="entity_treemap")
328
 
329
  value_counts = df['entity_group'].value_counts().reset_index()
330
  value_counts.columns = ['entity_group', 'count']
 
331
  col1, col2 = st.columns(2)
332
+
333
  with col1:
334
  st.subheader("Pie Chart", divider="rainbow")
335
  fig1 = px.pie(value_counts, values='count', names='entity_group',
 
337
  title='Percentage of Predicted Labels')
338
  fig1.update_traces(textposition='inside', textinfo='percent+label')
339
  st.plotly_chart(fig1, use_container_width=True)
340
+
341
+ if comet_initialized and experiment:
342
  experiment.log_figure(figure=fig1, figure_name="label_pie_chart")
343
+
344
  with col2:
345
  st.subheader("Bar Chart", divider="rainbow")
346
  fig2 = px.bar(value_counts, x="count", y="entity_group", color="entity_group",
347
  text_auto=True, title='Occurrences of Predicted Labels')
348
  st.plotly_chart(fig2, use_container_width=True)
349
+
350
+ if comet_initialized and experiment:
351
  experiment.log_figure(figure=fig2, figure_name="label_bar_chart")
352
+ else: # This else corresponds to "if not df.empty:"
353
  st.warning("No entities were extracted from the provided text.")
 
 
354
 
355
  dfa = pd.DataFrame(
356
  data={
357
+ 'Column Name': ['word', 'entity_group','score', 'start', 'end'],
358
+ 'Description': [
359
+ 'entity extracted from your text data',
360
+ 'label (tag) assigned to a given extracted entity',
361
+ 'accuracy score; how accurately a tag has been assigned to a given entity',
362
+ 'index of the start of the corresponding entity',
363
+ 'index of the end of the corresponding entity',
364
+ ]
365
  }
366
  )
367
+
368
  buf = io.BytesIO()
369
  with zipfile.ZipFile(buf, "w") as myzip:
370
+ if not df.empty: # Only write if df is not empty
371
  myzip.writestr("Summary_of_results.csv", df.to_csv(index=False))
372
  myzip.writestr("Glossary_of_tags.csv", dfa.to_csv(index=False))
373
+
374
  with stylable_container(
375
+ key="download_button",
376
+ css_styles="""button { background-color: yellow; border: 1px solid black; padding: 5px; color: black; }""",
377
+ ):
378
  st.download_button(
379
+ label="Download zip file",
380
+ data=buf.getvalue(),
381
+ file_name="nlpblogs_ner_results.zip",
382
+ mime="application/zip",
383
+ )
 
 
384
  st.divider()
385
+ else: # This else corresponds to "if text_to_process and len(text_to_process.strip()) > 0:"
386
  st.warning("No meaningful text found to process. Please enter a URL or text.")
 
 
387
  except Exception as e:
388
  st.error(f"An unexpected error occurred: {e}")
389
  finally:
390
  if comet_initialized and experiment:
391
  experiment.end()
392
+
393
+ end_time = time.time() # End timer here
394
+ elapsed_time = end_time - start_time
395
+ st.info(f"Results processed in **{elapsed_time:.2f} seconds**.")
396
+ st.write(f"Number of times you requested results: **{st.session_state['source_type_attempts']}/{max_attempts}**")