Maria Tsilimos
Create app.py
1189b42 unverified
raw
history blame
8.37 kB
import streamlit as st
import time
import pandas as pd
import io
from transformers import pipeline
from streamlit_extras.stylable_container import stylable_container
import plotly.express as px
import zipfile
from PyPDF2 import PdfReader
import docx
import os
from comet_ml import Experiment
import re
import numpy as np
st.subheader("4-Named Entity Recognition Web App", divider = "rainbow")
st.link_button("by nlpblogs", "https://nlpblogs.com", type = "tertiary")
expander = st.expander("**Important notes on the 4-Named Entity Recognition Web App**")
expander.write('''
**Named Entities:**
This 4-Named Entity Recognition Web App predicts four (4) labels (“person”, “location”, “organization”, “miscellaneous”). 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.
**How to Use:**
Upload your .pdf or .docx file. Then, click the 'Results' button to extract and tag entities in your text data.
**Usage Limits:**
You can request results up to 10 times.
**Customization:**
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.
**Technical issues:**
If your connection times out, please refresh the page or reopen the app's URL.
For any errors or inquiries, please contact us at [email protected]
''')
with st.sidebar:
container = st.container(border=True)
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.")
st.subheader("Related NLP Web Apps", divider = "rainbow")
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")
COMET_API_KEY = os.environ.get("COMET_API_KEY")
COMET_WORKSPACE = os.environ.get("COMET_WORKSPACE")
COMET_PROJECT_NAME = os.environ.get("COMET_PROJECT_NAME")
if COMET_API_KEY and COMET_WORKSPACE and COMET_PROJECT_NAME:
comet_initialized = True
else:
comet_initialized = False
st.warning("Comet ML not initialized. Check environment variables.")
if 'file_upload_attempts' not in st.session_state:
st.session_state['file_upload_attempts'] = 0
max_attempts = 10
upload_file = st.file_uploader("Upload your file. Accepted file formats include: .pdf, .docx", type=['pdf', 'docx'])
text = None
df = None
if upload_file is not None:
file_extension = upload_file.name.split('.')[-1].lower()
if file_extension == 'pdf':
try:
pdf_reader = PdfReader(upload_file)
text = ""
for page in pdf_reader.pages:
text += page.extract_text()
st.write("Due to security protocols, the file content is hidden.")
except Exception as e:
st.error(f"An error occurred while reading PDF: {e}")
elif file_extension == 'docx':
try:
doc = docx.Document(upload_file)
text = "\n".join([para.text for para in doc.paragraphs])
st.write("Due to security protocols, the file content is hidden.")
except Exception as e:
st.error(f"An error occurred while reading docx: {e}")
else:
st.warning("Unsupported file type.")
st.stop()
st.divider()
if st.button("Results"):
if st.session_state['file_upload_attempts'] >= max_attempts:
st.error(f"You have requested results {max_attempts} times. You have reached your daily request limit.")
st.stop()
st.session_state['file_upload_attempts'] += 1
with st.spinner("Wait for it...", show_time=True):
time.sleep(5)
model = pipeline("token-classification", model="dslim/distilbert-NER", aggregation_strategy = "max")
text1 = model(text)
df1 = pd.DataFrame(text1)
pattern = r'[^\w\s]'
df1['word'] = df1['word'].replace(pattern, '', regex=True)
df2 = df1.replace('', 'Unknown')
df = df2.dropna()
if comet_initialized:
experiment = Experiment(
api_key=COMET_API_KEY,
workspace=COMET_WORKSPACE,
project_name=COMET_PROJECT_NAME,
)
experiment.log_parameter("input_text", text)
experiment.log_table("predicted_entities", df)
properties = {"border": "2px solid gray", "color": "blue", "font-size": "16px"}
df_styled = df.style.set_properties(**properties)
st.dataframe(df_styled)
with st.expander("See Glossary of tags"):
st.write('''
'**word**': ['entity extracted from your text data']
'**score**': ['accuracy score; how accurately a tag has been assigned to a given entity']
'**entity_group**': ['label (tag) assigned to a given extracted entity']
'**start**': ['index of the start of the corresponding entity']
'**end**': ['index of the end of the corresponding entity']
''')
if df is not None:
fig = px.treemap(df, path=[px.Constant("all"), 'word', 'entity_group'],
values='score', color='entity_group')
fig.update_layout(margin = dict(t=50, l=25, r=25, b=25))
st.subheader("Tree map", divider = "rainbow")
st.plotly_chart(fig)
if comet_initialized:
experiment.log_figure(figure=fig, figure_name="entity_treemap")
if df is not None:
value_counts1 = df['entity_group'].value_counts()
df1 = pd.DataFrame(value_counts1)
final_df = df1.reset_index().rename(columns={"index": "entity_group"})
col1, col2 = st.columns(2)
with col1:
fig1 = px.pie(final_df, values='count', names='entity_group', hover_data=['count'], labels={'count': 'count'}, title='Percentage of predicted labels')
fig1.update_traces(textposition='inside', textinfo='percent+label')
st.subheader("Pie Chart", divider = "rainbow")
st.plotly_chart(fig1)
if comet_initialized:
experiment.log_figure(figure=fig1, figure_name="label_pie_chart")
with col2:
fig2 = px.bar(final_df, x="count", y="entity_group", color="entity_group", text_auto=True, title='Occurrences of predicted labels')
st.subheader("Bar Chart", divider = "rainbow")
st.plotly_chart(fig2)
if comet_initialized:
experiment.log_figure(figure=fig2, figure_name="label_bar_chart")
dfa = pd.DataFrame(
data={
'word': ['entity extracted from your text data'], 'score': ['accuracy score; how accurately a tag has been assigned to a given entity'], 'entity_group': ['label (tag) assigned to a given extracted entity'],
'start': ['index of the start of the corresponding entity'],
'end': ['index of the end of the corresponding entity'],
})
buf = io.BytesIO()
with zipfile.ZipFile(buf, "w") as myzip:
myzip.writestr("Summary of the results.csv", df.to_csv(index=False))
myzip.writestr("Glossary of tags.csv", dfa.to_csv(index=False))
with stylable_container(
key="download_button",
css_styles="""button { background-color: yellow; border: 1px solid black; padding: 5px; color: black; }""",
):
st.download_button(
label="Download zip file",
data=buf.getvalue(),
file_name="zip file.zip",
mime="application/zip",
)
if comet_initialized:
experiment.log_asset(buf.getvalue(), file_name="downloadable_results.zip")
st.divider()
if comet_initialized:
experiment.end()
st.write(f"Number of times you requested results: {st.session_state['file_upload_attempts']}/{max_attempts}")