Spaces:
Sleeping
Sleeping
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +22 -88
src/streamlit_app.py
CHANGED
|
@@ -8,8 +8,6 @@ import plotly.express as px
|
|
| 8 |
import zipfile
|
| 9 |
import json
|
| 10 |
import hashlib
|
| 11 |
-
|
| 12 |
-
|
| 13 |
from typing import Optional
|
| 14 |
from gliner import GLiNER
|
| 15 |
from comet_ml import Experiment
|
|
@@ -18,8 +16,6 @@ from comet_ml import Experiment
|
|
| 18 |
st.set_page_config(layout="wide", page_title="NER")
|
| 19 |
st.subheader("HR.ai", divider="green")
|
| 20 |
st.link_button("by nlpblogs", "https://nlpblogs.com", type="tertiary")
|
| 21 |
-
|
| 22 |
-
|
| 23 |
st.markdown(
|
| 24 |
"""
|
| 25 |
<style>
|
|
@@ -67,40 +63,11 @@ st.markdown(
|
|
| 67 |
background-color: #D4F4D4;
|
| 68 |
color: #000000;
|
| 69 |
}
|
| 70 |
-
|
| 71 |
</style>
|
| 72 |
""",
|
| 73 |
-
unsafe_allow_html=True
|
| 74 |
-
)
|
| 75 |
-
|
| 76 |
expander = st.expander("**Important notes**")
|
| 77 |
-
expander.write("""
|
| 78 |
-
**How to Use the HR.ai web app:**
|
| 79 |
-
|
| 80 |
-
1. Type or paste your text into the text area, then press Ctrl + Enter.
|
| 81 |
-
2. Click the 'Results' button to extract and tag entities in your text data.
|
| 82 |
-
|
| 83 |
-
Results are presented in easy-to-read tables, visualized in an interactive tree map, pie chart and bar chart, and are available for download along with a Glossary of tags.
|
| 84 |
-
|
| 85 |
-
**How to Use the Question-Answering feature:**
|
| 86 |
-
|
| 87 |
-
1. Type or paste your text into the text area, then press Ctrl + Enter.
|
| 88 |
-
2. Click the 'Add Question' button to add your question to the Record of Questions. You can manage your questions by deleting them one by one.
|
| 89 |
-
3. Click the 'Extract Answers' button to extract the answer to your question.
|
| 90 |
-
|
| 91 |
-
Results are presented in an easy-to-read table, visualized in an interactive tree map, and is available for download.
|
| 92 |
-
|
| 93 |
-
**Entities:** "Email", "Phone_number", "Street_address", "City", "Country", "Date_of_birth", "Marital_status", "Person", "Full_time", "Part_time", "Contract", "Terminated", "Retired", "Job_title", "Date", "Organization", "Role", "Performance_score", "Leave_of_absence", "Retirement_plan", "Bonus", "Stock_options", "Health_insurance", "Pay_rate", "Annual_salary", "Tax", "Deductions", "Interview_type", "Applicant", "Referral", "Job_board", "Recruiter", "Offer_letter", "Agreement", "Certification", "Skill"
|
| 94 |
-
|
| 95 |
-
**Usage Limits:** You can request results unlimited times for one (1) month.
|
| 96 |
-
|
| 97 |
-
**Supported Languages:** English
|
| 98 |
-
|
| 99 |
-
**Technical issues:** If your connection times out, please refresh the page or reopen the app's URL.
|
| 100 |
-
|
| 101 |
-
For any errors or inquiries, please contact us at info@nlpblogs.com""")
|
| 102 |
-
|
| 103 |
-
|
| 104 |
with st.sidebar:
|
| 105 |
st.write("Use the following code to embed the web app on your website. Feel free to adjust the width and height values to fit your page.")
|
| 106 |
code = '''
|
|
@@ -117,16 +84,13 @@ with st.sidebar:
|
|
| 117 |
st.divider()
|
| 118 |
st.subheader("🚀 Ready to build your own AI Web App?", divider="green")
|
| 119 |
st.link_button("AI Web App Builder", "https://nlpblogs.com/build-your-named-entity-recognition-app/", type="primary")
|
| 120 |
-
|
| 121 |
# --- Comet ML Setup ---
|
| 122 |
COMET_API_KEY = os.environ.get("COMET_API_KEY")
|
| 123 |
COMET_WORKSPACE = os.environ.get("COMET_WORKSPACE")
|
| 124 |
COMET_PROJECT_NAME = os.environ.get("COMET_PROJECT_NAME")
|
| 125 |
comet_initialized = bool(COMET_API_KEY and COMET_WORKSPACE and COMET_PROJECT_NAME)
|
| 126 |
-
|
| 127 |
if not comet_initialized:
|
| 128 |
st.warning("Comet ML not initialized. Check environment variables.")
|
| 129 |
-
|
| 130 |
# --- Model Loading and Caching ---
|
| 131 |
@st.cache_resource
|
| 132 |
def load_gliner_model(model_name):
|
|
@@ -139,10 +103,8 @@ def load_gliner_model(model_name):
|
|
| 139 |
except Exception as e:
|
| 140 |
st.error(f"Error loading the GLiNER model: {e}")
|
| 141 |
st.stop()
|
| 142 |
-
|
| 143 |
# --- HR_AI Model Labels and Mappings ---
|
| 144 |
labels = ["Email", "Phone_number", "Street_address", "City", "Country", "Date_of_birth", "Marital_status", "Person", "Full_time", "Part_time", "Contract", "Terminated", "Retired", "Job_title", "Date", "Organization", "Role", "Performance_score", "Leave_of_absence", "Retirement_plan", "Bonus", "Stock_options", "Health_insurance", "Pay_rate", "Annual_salary", "Tax", "Deductions", "Interview_type", "Applicant", "Referral", "Job_board", "Recruiter", "Offer_letter", "Agreement", "Certification", "Skill"]
|
| 145 |
-
|
| 146 |
category_mapping = {
|
| 147 |
"Contact Information": ["Email", "Phone_number", "Street_address", "City", "Country"],
|
| 148 |
"Personal Details": ["Date_of_birth", "Marital_status", "Person"],
|
|
@@ -155,51 +117,53 @@ category_mapping = {
|
|
| 155 |
"Deductions": ["Tax", "Deductions"],
|
| 156 |
"Recruitment & Sourcing": ["Interview_type", "Applicant", "Referral", "Job_board", "Recruiter"],
|
| 157 |
"Legal & Compliance": ["Offer_letter", "Agreement"],
|
| 158 |
-
"Professional_Development": ["Certification", "Skill"]
|
| 159 |
-
}
|
| 160 |
reverse_category_mapping = {label: category for category, label_list in category_mapping.items() for label in label_list}
|
| 161 |
-
|
| 162 |
# --- InfoFinder Helpers ---
|
| 163 |
if 'user_labels' not in st.session_state:
|
| 164 |
st.session_state.user_labels = []
|
| 165 |
-
|
| 166 |
def get_stable_color(label):
|
| 167 |
hash_object = hashlib.sha1(label.encode('utf-8'))
|
| 168 |
hex_dig = hash_object.hexdigest()
|
| 169 |
return '#' + hex_dig[:6]
|
| 170 |
-
|
| 171 |
# --- Main App with Tabs ---
|
| 172 |
tab1, tab2 = st.tabs(["HR.ai", "Question-Answering"])
|
| 173 |
-
|
| 174 |
with tab1:
|
| 175 |
-
|
| 176 |
-
|
| 177 |
# Load model for this tab
|
| 178 |
model_hr = load_gliner_model("HR_AI")
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 182 |
def clear_text_hr():
|
| 183 |
st.session_state['my_text_area_hr'] = ""
|
| 184 |
-
|
| 185 |
st.button("Clear text", on_click=clear_text_hr, key="clear_hr")
|
| 186 |
-
|
| 187 |
if st.button("Results"):
|
| 188 |
start_time = time.time()
|
|
|
|
|
|
|
| 189 |
if not text.strip():
|
| 190 |
st.warning("Please enter some text to extract entities.")
|
|
|
|
|
|
|
| 191 |
else:
|
| 192 |
with st.spinner("Extracting entities...", show_time=True):
|
| 193 |
entities = model_hr.predict_entities(text, labels)
|
| 194 |
df = pd.DataFrame(entities)
|
| 195 |
-
|
| 196 |
if not df.empty:
|
| 197 |
df['category'] = df['label'].map(reverse_category_mapping)
|
| 198 |
if comet_initialized:
|
| 199 |
experiment = Experiment(api_key=COMET_API_KEY, workspace=COMET_WORKSPACE, project_name=COMET_PROJECT_NAME)
|
| 200 |
experiment.log_parameter("input_text", text)
|
| 201 |
experiment.log_table("predicted_entities", df)
|
| 202 |
-
|
| 203 |
st.subheader("Grouped Entities by Category", divider="green")
|
| 204 |
category_names = sorted(list(category_mapping.keys()))
|
| 205 |
category_tabs_hr = st.tabs(category_names)
|
|
@@ -210,7 +174,6 @@ with tab1:
|
|
| 210 |
st.dataframe(df_category_filtered.drop(columns=['category']), use_container_width=True)
|
| 211 |
else:
|
| 212 |
st.info(f"No entities found for the '{category_name}' category.")
|
| 213 |
-
|
| 214 |
with st.expander("See Glossary of tags"):
|
| 215 |
st.write('''
|
| 216 |
- **text**: ['entity extracted from your text data']
|
|
@@ -220,12 +183,10 @@ with tab1:
|
|
| 220 |
- **end**: ['index of the end of the corresponding entity']
|
| 221 |
''')
|
| 222 |
st.divider()
|
| 223 |
-
|
| 224 |
st.subheader("Candidate Card", divider="green")
|
| 225 |
fig_treemap = px.treemap(df, path=[px.Constant("all"), 'category', 'label', 'text'], values='score', color='category')
|
| 226 |
fig_treemap.update_layout(margin=dict(t=50, l=25, r=25, b=25), paper_bgcolor='#F5FFFA', plot_bgcolor='#F5FFFA')
|
| 227 |
st.plotly_chart(fig_treemap)
|
| 228 |
-
|
| 229 |
col1, col2 = st.columns(2)
|
| 230 |
with col1:
|
| 231 |
st.subheader("Pie chart", divider="green")
|
|
@@ -235,13 +196,11 @@ with tab1:
|
|
| 235 |
fig_pie.update_traces(textposition='inside', textinfo='percent+label')
|
| 236 |
fig_pie.update_layout(paper_bgcolor='#F5FFFA', plot_bgcolor='#F5FFFA')
|
| 237 |
st.plotly_chart(fig_pie)
|
| 238 |
-
|
| 239 |
with col2:
|
| 240 |
st.subheader("Bar chart", divider="green")
|
| 241 |
fig_bar = px.bar(grouped_counts, x="count", y="category", color="category", text_auto=True, title='Occurrences of predicted categories')
|
| 242 |
fig_bar.update_layout(paper_bgcolor='#F5FFFA', plot_bgcolor='#F5FFFA')
|
| 243 |
st.plotly_chart(fig_bar)
|
| 244 |
-
|
| 245 |
st.subheader("Most Frequent Entities", divider="green")
|
| 246 |
word_counts = df['text'].value_counts().reset_index()
|
| 247 |
word_counts.columns = ['Entity', 'Count']
|
|
@@ -253,50 +212,37 @@ with tab1:
|
|
| 253 |
st.plotly_chart(fig_repeating_bar)
|
| 254 |
else:
|
| 255 |
st.warning("No entities were found that occur more than once.")
|
| 256 |
-
|
| 257 |
st.divider()
|
| 258 |
-
|
| 259 |
dfa = pd.DataFrame(data={'Column Name': ['text', 'label', 'score', 'start', 'end'], 'Description': ['entity extracted from your text data', 'label (tag) assigned to a given extracted entity', 'accuracy score; how accurately a tag has been assigned to a given entity', 'index of the start of the corresponding entity', 'index of the end of the corresponding entity']})
|
| 260 |
buf = io.BytesIO()
|
| 261 |
with zipfile.ZipFile(buf, "w") as myzip:
|
| 262 |
myzip.writestr("Summary of the results.csv", df.to_csv(index=False))
|
| 263 |
myzip.writestr("Glossary of tags.csv", dfa.to_csv(index=False))
|
| 264 |
-
|
| 265 |
st.download_button(
|
| 266 |
label="Download results and glossary (zip)",
|
| 267 |
data=buf.getvalue(),
|
| 268 |
file_name="nlpblogs_results.zip",
|
| 269 |
mime="application/zip",
|
| 270 |
)
|
| 271 |
-
|
| 272 |
if comet_initialized:
|
| 273 |
experiment.log_figure(figure=fig_treemap, figure_name="entity_treemap_categories")
|
| 274 |
experiment.end()
|
| 275 |
else:
|
| 276 |
st.warning("No entities were found in the provided text.")
|
| 277 |
-
|
| 278 |
end_time = time.time()
|
| 279 |
elapsed_time = end_time - start_time
|
| 280 |
st.text("")
|
| 281 |
st.text("")
|
| 282 |
st.info(f"Results processed in **{elapsed_time:.2f} seconds**.")
|
| 283 |
-
|
| 284 |
with tab2:
|
| 285 |
-
|
| 286 |
-
|
| 287 |
# Load model for this tab
|
| 288 |
model_qa = load_gliner_model("InfoFinder")
|
| 289 |
-
|
| 290 |
user_text = st.text_area("Type or paste your text below, and then press Ctrl + Enter", height=250, key='my_text_area_infofinder')
|
| 291 |
-
|
| 292 |
def clear_text_qa():
|
| 293 |
st.session_state['my_text_area_infofinder'] = ""
|
| 294 |
-
|
| 295 |
st.button("Clear text", on_click=clear_text_qa, key="clear_qa")
|
| 296 |
-
|
| 297 |
st.subheader("Question-Answering", divider="green")
|
| 298 |
question_input = st.text_input("Ask wh-questions. **Wh-questions begin with what, when, where, who, whom, which, whose, why and how. We use them to ask for specific information.**")
|
| 299 |
-
|
| 300 |
if st.button("Add Question"):
|
| 301 |
if question_input:
|
| 302 |
if question_input not in st.session_state.user_labels:
|
|
@@ -306,10 +252,8 @@ with tab2:
|
|
| 306 |
st.warning("This question has already been added.")
|
| 307 |
else:
|
| 308 |
st.warning("Please enter a question.")
|
| 309 |
-
|
| 310 |
st.markdown("---")
|
| 311 |
st.subheader("Record of Questions", divider="green")
|
| 312 |
-
|
| 313 |
if st.session_state.user_labels:
|
| 314 |
for i, label in enumerate(st.session_state.user_labels):
|
| 315 |
col_list, col_delete = st.columns([0.9, 0.1])
|
|
@@ -321,9 +265,7 @@ with tab2:
|
|
| 321 |
st.rerun()
|
| 322 |
else:
|
| 323 |
st.info("No questions defined yet. Use the input above to add one.")
|
| 324 |
-
|
| 325 |
st.divider()
|
| 326 |
-
|
| 327 |
if st.button("Extract Answers"):
|
| 328 |
if not user_text.strip():
|
| 329 |
st.warning("Please enter some text to analyze.")
|
|
@@ -334,7 +276,6 @@ with tab2:
|
|
| 334 |
experiment = Experiment(api_key=COMET_API_KEY, workspace=COMET_WORKSPACE, project_name=COMET_PROJECT_NAME)
|
| 335 |
experiment.log_parameter("input_text_length", len(user_text))
|
| 336 |
experiment.log_parameter("defined_labels", st.session_state.user_labels)
|
| 337 |
-
|
| 338 |
start_time = time.time()
|
| 339 |
with st.spinner("Analyzing text...", show_time=True):
|
| 340 |
try:
|
|
@@ -342,27 +283,22 @@ with tab2:
|
|
| 342 |
end_time = time.time()
|
| 343 |
elapsed_time = end_time - start_time
|
| 344 |
st.info(f"Processing took **{elapsed_time:.2f} seconds**.")
|
| 345 |
-
|
| 346 |
if entities:
|
| 347 |
df1 = pd.DataFrame(entities)
|
| 348 |
df2 = df1[['label', 'text', 'score']]
|
| 349 |
df = df2.rename(columns={'label': 'question', 'text': 'answer'})
|
| 350 |
-
|
| 351 |
st.subheader("Extracted Answers", divider="green")
|
| 352 |
expander = st.expander("**Download**")
|
| 353 |
-
expander.write("""
|
| 354 |
-
|
| 355 |
""")
|
| 356 |
st.dataframe(df, use_container_width=True)
|
| 357 |
-
|
| 358 |
st.subheader("Tree map", divider="green")
|
| 359 |
all_labels = df['question'].unique()
|
| 360 |
label_color_map = {label: get_stable_color(label) for label in all_labels}
|
| 361 |
fig_treemap = px.treemap(df, path=[px.Constant("all"), 'question', 'answer'], values='score', color='question', color_discrete_map=label_color_map)
|
| 362 |
fig_treemap.update_layout(margin=dict(t=50, l=25, r=25, b=25), paper_bgcolor='#F3E5F5', plot_bgcolor='#F3E5F5')
|
| 363 |
st.plotly_chart(fig_treemap)
|
| 364 |
-
|
| 365 |
-
|
| 366 |
if comet_initialized:
|
| 367 |
experiment.log_metric("processing_time_seconds", elapsed_time)
|
| 368 |
experiment.log_table("predicted_entities", df)
|
|
@@ -377,6 +313,4 @@ with tab2:
|
|
| 377 |
st.write(f"Error details: {e}")
|
| 378 |
if comet_initialized:
|
| 379 |
experiment.log_text(f"Error: {e}")
|
| 380 |
-
experiment.end()
|
| 381 |
-
|
| 382 |
-
|
|
|
|
| 8 |
import zipfile
|
| 9 |
import json
|
| 10 |
import hashlib
|
|
|
|
|
|
|
| 11 |
from typing import Optional
|
| 12 |
from gliner import GLiNER
|
| 13 |
from comet_ml import Experiment
|
|
|
|
| 16 |
st.set_page_config(layout="wide", page_title="NER")
|
| 17 |
st.subheader("HR.ai", divider="green")
|
| 18 |
st.link_button("by nlpblogs", "https://nlpblogs.com", type="tertiary")
|
|
|
|
|
|
|
| 19 |
st.markdown(
|
| 20 |
"""
|
| 21 |
<style>
|
|
|
|
| 63 |
background-color: #D4F4D4;
|
| 64 |
color: #000000;
|
| 65 |
}
|
|
|
|
| 66 |
</style>
|
| 67 |
""",
|
| 68 |
+
unsafe_allow_html=True)
|
|
|
|
|
|
|
| 69 |
expander = st.expander("**Important notes**")
|
| 70 |
+
expander.write(""" **How to Use the HR.ai web app:** 1. Type or paste your text into the text area, then press Ctrl + Enter.2. Click the 'Results' button to extract and tag entities in your text data. Results are presented in easy-to-read tables, 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 the Question-Answering feature:**1. Type or paste your text into the text area, then press Ctrl + Enter. 2. Click the 'Add Question' button to add your question to the Record of Questions. You can manage your questions by deleting them one by one.3. Click the 'Extract Answers' button to extract the answer to your question.Results are presented in an easy-to-read table, visualized in an interactive tree map, and is available for download. **Entities:** "Email", "Phone_number", "Street_address", "City", "Country", "Date_of_birth", "Marital_status", "Person", "Full_time", "Part_time", "Contract", "Terminated", "Retired", "Job_title", "Date", "Organization", "Role", "Performance_score", "Leave_of_absence", "Retirement_plan", "Bonus", "Stock_options", "Health_insurance", "Pay_rate", "Annual_salary", "Tax", "Deductions", "Interview_type", "Applicant", "Referral", "Job_board", "Recruiter", "Offer_letter", "Agreement", "Certification", "Skill"**Usage Limits:** You can request results unlimited times for one (1) month. **Supported Languages:** English **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 info@nlpblogs.com""")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
with st.sidebar:
|
| 72 |
st.write("Use the following code to embed the web app on your website. Feel free to adjust the width and height values to fit your page.")
|
| 73 |
code = '''
|
|
|
|
| 84 |
st.divider()
|
| 85 |
st.subheader("🚀 Ready to build your own AI Web App?", divider="green")
|
| 86 |
st.link_button("AI Web App Builder", "https://nlpblogs.com/build-your-named-entity-recognition-app/", type="primary")
|
|
|
|
| 87 |
# --- Comet ML Setup ---
|
| 88 |
COMET_API_KEY = os.environ.get("COMET_API_KEY")
|
| 89 |
COMET_WORKSPACE = os.environ.get("COMET_WORKSPACE")
|
| 90 |
COMET_PROJECT_NAME = os.environ.get("COMET_PROJECT_NAME")
|
| 91 |
comet_initialized = bool(COMET_API_KEY and COMET_WORKSPACE and COMET_PROJECT_NAME)
|
|
|
|
| 92 |
if not comet_initialized:
|
| 93 |
st.warning("Comet ML not initialized. Check environment variables.")
|
|
|
|
| 94 |
# --- Model Loading and Caching ---
|
| 95 |
@st.cache_resource
|
| 96 |
def load_gliner_model(model_name):
|
|
|
|
| 103 |
except Exception as e:
|
| 104 |
st.error(f"Error loading the GLiNER model: {e}")
|
| 105 |
st.stop()
|
|
|
|
| 106 |
# --- HR_AI Model Labels and Mappings ---
|
| 107 |
labels = ["Email", "Phone_number", "Street_address", "City", "Country", "Date_of_birth", "Marital_status", "Person", "Full_time", "Part_time", "Contract", "Terminated", "Retired", "Job_title", "Date", "Organization", "Role", "Performance_score", "Leave_of_absence", "Retirement_plan", "Bonus", "Stock_options", "Health_insurance", "Pay_rate", "Annual_salary", "Tax", "Deductions", "Interview_type", "Applicant", "Referral", "Job_board", "Recruiter", "Offer_letter", "Agreement", "Certification", "Skill"]
|
|
|
|
| 108 |
category_mapping = {
|
| 109 |
"Contact Information": ["Email", "Phone_number", "Street_address", "City", "Country"],
|
| 110 |
"Personal Details": ["Date_of_birth", "Marital_status", "Person"],
|
|
|
|
| 117 |
"Deductions": ["Tax", "Deductions"],
|
| 118 |
"Recruitment & Sourcing": ["Interview_type", "Applicant", "Referral", "Job_board", "Recruiter"],
|
| 119 |
"Legal & Compliance": ["Offer_letter", "Agreement"],
|
| 120 |
+
"Professional_Development": ["Certification", "Skill"]}
|
|
|
|
| 121 |
reverse_category_mapping = {label: category for category, label_list in category_mapping.items() for label in label_list}
|
|
|
|
| 122 |
# --- InfoFinder Helpers ---
|
| 123 |
if 'user_labels' not in st.session_state:
|
| 124 |
st.session_state.user_labels = []
|
|
|
|
| 125 |
def get_stable_color(label):
|
| 126 |
hash_object = hashlib.sha1(label.encode('utf-8'))
|
| 127 |
hex_dig = hash_object.hexdigest()
|
| 128 |
return '#' + hex_dig[:6]
|
|
|
|
| 129 |
# --- Main App with Tabs ---
|
| 130 |
tab1, tab2 = st.tabs(["HR.ai", "Question-Answering"])
|
|
|
|
| 131 |
with tab1:
|
|
|
|
|
|
|
| 132 |
# Load model for this tab
|
| 133 |
model_hr = load_gliner_model("HR_AI")
|
| 134 |
+
|
| 135 |
+
# Define the word limit
|
| 136 |
+
word_limit = 200
|
| 137 |
+
|
| 138 |
+
text = st.text_area("Type or paste your text below (max 200 words), and then press Ctrl + Enter", height=250, key='my_text_area_hr')
|
| 139 |
+
|
| 140 |
+
# Calculate and display the word count
|
| 141 |
+
word_count = len(text.split())
|
| 142 |
+
st.markdown(f"**Word count:** {word_count}/{word_limit}")
|
| 143 |
+
|
| 144 |
def clear_text_hr():
|
| 145 |
st.session_state['my_text_area_hr'] = ""
|
| 146 |
+
|
| 147 |
st.button("Clear text", on_click=clear_text_hr, key="clear_hr")
|
| 148 |
+
|
| 149 |
if st.button("Results"):
|
| 150 |
start_time = time.time()
|
| 151 |
+
|
| 152 |
+
# Check for word limit and empty text
|
| 153 |
if not text.strip():
|
| 154 |
st.warning("Please enter some text to extract entities.")
|
| 155 |
+
elif word_count > word_limit:
|
| 156 |
+
st.warning(f"Your text exceeds the {word_limit} word limit. Please shorten it to continue.")
|
| 157 |
else:
|
| 158 |
with st.spinner("Extracting entities...", show_time=True):
|
| 159 |
entities = model_hr.predict_entities(text, labels)
|
| 160 |
df = pd.DataFrame(entities)
|
|
|
|
| 161 |
if not df.empty:
|
| 162 |
df['category'] = df['label'].map(reverse_category_mapping)
|
| 163 |
if comet_initialized:
|
| 164 |
experiment = Experiment(api_key=COMET_API_KEY, workspace=COMET_WORKSPACE, project_name=COMET_PROJECT_NAME)
|
| 165 |
experiment.log_parameter("input_text", text)
|
| 166 |
experiment.log_table("predicted_entities", df)
|
|
|
|
| 167 |
st.subheader("Grouped Entities by Category", divider="green")
|
| 168 |
category_names = sorted(list(category_mapping.keys()))
|
| 169 |
category_tabs_hr = st.tabs(category_names)
|
|
|
|
| 174 |
st.dataframe(df_category_filtered.drop(columns=['category']), use_container_width=True)
|
| 175 |
else:
|
| 176 |
st.info(f"No entities found for the '{category_name}' category.")
|
|
|
|
| 177 |
with st.expander("See Glossary of tags"):
|
| 178 |
st.write('''
|
| 179 |
- **text**: ['entity extracted from your text data']
|
|
|
|
| 183 |
- **end**: ['index of the end of the corresponding entity']
|
| 184 |
''')
|
| 185 |
st.divider()
|
|
|
|
| 186 |
st.subheader("Candidate Card", divider="green")
|
| 187 |
fig_treemap = px.treemap(df, path=[px.Constant("all"), 'category', 'label', 'text'], values='score', color='category')
|
| 188 |
fig_treemap.update_layout(margin=dict(t=50, l=25, r=25, b=25), paper_bgcolor='#F5FFFA', plot_bgcolor='#F5FFFA')
|
| 189 |
st.plotly_chart(fig_treemap)
|
|
|
|
| 190 |
col1, col2 = st.columns(2)
|
| 191 |
with col1:
|
| 192 |
st.subheader("Pie chart", divider="green")
|
|
|
|
| 196 |
fig_pie.update_traces(textposition='inside', textinfo='percent+label')
|
| 197 |
fig_pie.update_layout(paper_bgcolor='#F5FFFA', plot_bgcolor='#F5FFFA')
|
| 198 |
st.plotly_chart(fig_pie)
|
|
|
|
| 199 |
with col2:
|
| 200 |
st.subheader("Bar chart", divider="green")
|
| 201 |
fig_bar = px.bar(grouped_counts, x="count", y="category", color="category", text_auto=True, title='Occurrences of predicted categories')
|
| 202 |
fig_bar.update_layout(paper_bgcolor='#F5FFFA', plot_bgcolor='#F5FFFA')
|
| 203 |
st.plotly_chart(fig_bar)
|
|
|
|
| 204 |
st.subheader("Most Frequent Entities", divider="green")
|
| 205 |
word_counts = df['text'].value_counts().reset_index()
|
| 206 |
word_counts.columns = ['Entity', 'Count']
|
|
|
|
| 212 |
st.plotly_chart(fig_repeating_bar)
|
| 213 |
else:
|
| 214 |
st.warning("No entities were found that occur more than once.")
|
|
|
|
| 215 |
st.divider()
|
|
|
|
| 216 |
dfa = pd.DataFrame(data={'Column Name': ['text', 'label', 'score', 'start', 'end'], 'Description': ['entity extracted from your text data', 'label (tag) assigned to a given extracted entity', 'accuracy score; how accurately a tag has been assigned to a given entity', 'index of the start of the corresponding entity', 'index of the end of the corresponding entity']})
|
| 217 |
buf = io.BytesIO()
|
| 218 |
with zipfile.ZipFile(buf, "w") as myzip:
|
| 219 |
myzip.writestr("Summary of the results.csv", df.to_csv(index=False))
|
| 220 |
myzip.writestr("Glossary of tags.csv", dfa.to_csv(index=False))
|
|
|
|
| 221 |
st.download_button(
|
| 222 |
label="Download results and glossary (zip)",
|
| 223 |
data=buf.getvalue(),
|
| 224 |
file_name="nlpblogs_results.zip",
|
| 225 |
mime="application/zip",
|
| 226 |
)
|
|
|
|
| 227 |
if comet_initialized:
|
| 228 |
experiment.log_figure(figure=fig_treemap, figure_name="entity_treemap_categories")
|
| 229 |
experiment.end()
|
| 230 |
else:
|
| 231 |
st.warning("No entities were found in the provided text.")
|
|
|
|
| 232 |
end_time = time.time()
|
| 233 |
elapsed_time = end_time - start_time
|
| 234 |
st.text("")
|
| 235 |
st.text("")
|
| 236 |
st.info(f"Results processed in **{elapsed_time:.2f} seconds**.")
|
|
|
|
| 237 |
with tab2:
|
|
|
|
|
|
|
| 238 |
# Load model for this tab
|
| 239 |
model_qa = load_gliner_model("InfoFinder")
|
|
|
|
| 240 |
user_text = st.text_area("Type or paste your text below, and then press Ctrl + Enter", height=250, key='my_text_area_infofinder')
|
|
|
|
| 241 |
def clear_text_qa():
|
| 242 |
st.session_state['my_text_area_infofinder'] = ""
|
|
|
|
| 243 |
st.button("Clear text", on_click=clear_text_qa, key="clear_qa")
|
|
|
|
| 244 |
st.subheader("Question-Answering", divider="green")
|
| 245 |
question_input = st.text_input("Ask wh-questions. **Wh-questions begin with what, when, where, who, whom, which, whose, why and how. We use them to ask for specific information.**")
|
|
|
|
| 246 |
if st.button("Add Question"):
|
| 247 |
if question_input:
|
| 248 |
if question_input not in st.session_state.user_labels:
|
|
|
|
| 252 |
st.warning("This question has already been added.")
|
| 253 |
else:
|
| 254 |
st.warning("Please enter a question.")
|
|
|
|
| 255 |
st.markdown("---")
|
| 256 |
st.subheader("Record of Questions", divider="green")
|
|
|
|
| 257 |
if st.session_state.user_labels:
|
| 258 |
for i, label in enumerate(st.session_state.user_labels):
|
| 259 |
col_list, col_delete = st.columns([0.9, 0.1])
|
|
|
|
| 265 |
st.rerun()
|
| 266 |
else:
|
| 267 |
st.info("No questions defined yet. Use the input above to add one.")
|
|
|
|
| 268 |
st.divider()
|
|
|
|
| 269 |
if st.button("Extract Answers"):
|
| 270 |
if not user_text.strip():
|
| 271 |
st.warning("Please enter some text to analyze.")
|
|
|
|
| 276 |
experiment = Experiment(api_key=COMET_API_KEY, workspace=COMET_WORKSPACE, project_name=COMET_PROJECT_NAME)
|
| 277 |
experiment.log_parameter("input_text_length", len(user_text))
|
| 278 |
experiment.log_parameter("defined_labels", st.session_state.user_labels)
|
|
|
|
| 279 |
start_time = time.time()
|
| 280 |
with st.spinner("Analyzing text...", show_time=True):
|
| 281 |
try:
|
|
|
|
| 283 |
end_time = time.time()
|
| 284 |
elapsed_time = end_time - start_time
|
| 285 |
st.info(f"Processing took **{elapsed_time:.2f} seconds**.")
|
|
|
|
| 286 |
if entities:
|
| 287 |
df1 = pd.DataFrame(entities)
|
| 288 |
df2 = df1[['label', 'text', 'score']]
|
| 289 |
df = df2.rename(columns={'label': 'question', 'text': 'answer'})
|
|
|
|
| 290 |
st.subheader("Extracted Answers", divider="green")
|
| 291 |
expander = st.expander("**Download**")
|
| 292 |
+
expander.write("""
|
| 293 |
+
To download the data, simply hover your cursor over the table. A download icon will appear on the right side.
|
| 294 |
""")
|
| 295 |
st.dataframe(df, use_container_width=True)
|
|
|
|
| 296 |
st.subheader("Tree map", divider="green")
|
| 297 |
all_labels = df['question'].unique()
|
| 298 |
label_color_map = {label: get_stable_color(label) for label in all_labels}
|
| 299 |
fig_treemap = px.treemap(df, path=[px.Constant("all"), 'question', 'answer'], values='score', color='question', color_discrete_map=label_color_map)
|
| 300 |
fig_treemap.update_layout(margin=dict(t=50, l=25, r=25, b=25), paper_bgcolor='#F3E5F5', plot_bgcolor='#F3E5F5')
|
| 301 |
st.plotly_chart(fig_treemap)
|
|
|
|
|
|
|
| 302 |
if comet_initialized:
|
| 303 |
experiment.log_metric("processing_time_seconds", elapsed_time)
|
| 304 |
experiment.log_table("predicted_entities", df)
|
|
|
|
| 313 |
st.write(f"Error details: {e}")
|
| 314 |
if comet_initialized:
|
| 315 |
experiment.log_text(f"Error: {e}")
|
| 316 |
+
experiment.end()
|
|
|
|
|
|